Python Project Viewer

Outline of Test Cases

Create a function that receives a list of strings that are arithmetic problems and returns the problems arranged vertically and side-by-side.
The function should optionally take a second argument.
When the second argument is set to True, the answers should be displayed.

Code

See my replit code to run against the test modules

main.py

1
2
3
4
5
6
7
8
from pytest import main

from arithmetic_arranger import arithmetic_arranger

print(arithmetic_arranger(["32 + 698", "3801 - 2", "45 + 43", "123 + 49"]))

# Run unit tests automatically
main()

arithmetic_arranger.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import re  #Importing regular expression for search task

def arithmetic_arranger(problems,solve=False):

  #Error if more than 5 problems
  if len(problems)>5:
    return "Error: Too many problems."

  #Defining variables for each line
  top_line=""
  bottom_line=""
  dash_line=""
  solution_line=""
  arranged_line="" #Result string variable

  #find the sums that need to be calculated and put them in a list
  for problem in problems:
    num_list=problem.split()
    num1=num_list[0]
    operator=num_list[1]
    num2=num_list[2]

    #Error defining for validation
    if operator=="*" or operator=="/":
      return "Error: Operator must be '+' or '-'."

    if re.search("[^\d]",num1) or re.search("[^\d\+\-]",num2):
      return "Error: Numbers must only contain digits."

    if len(num1)>4 or len(num2)>4:
      return "Error: Numbers cannot be more than four digits."

    #Define the answers
    answer=""
    if operator=="+":
      answer=str(int(num1)+ int(num2))
    elif operator == "-":
      answer=str(int(num1) - int(num2))
      
    #Find the max length of the line needed
    line_length=max(len(num1),len(num2))+2

     #Find the value of the num1 line
    num1_line=""
    num1_line = str(num1.rjust(line_length))

    #Find the value of the num2 line
    num2_line=""
    num2_line =str(operator) + str(num2.rjust(line_length - 1))

    #Find the value of the dash line
    dashes=""
    for i in range(line_length):
      dashes +="-"

    #Find the value of the answer line
    answer_line=""
    answer_line += answer.rjust(line_length)

    #Formatting the space alignment of each line
    if problem != problems[-1]:
      top_line += num1_line + "    "
      bottom_line += num2_line + "    "
      dash_line += dashes + "    "
      solution_line += answer_line + "    "
    else:
      top_line += num1_line 
      bottom_line += num2_line 
      dash_line += dashes 
      solution_line += answer_line

  #Alignment of the arithemtic sum
  if solve==True:
    arranged_line = top_line + "\n" + bottom_line + "\n" + dash_line + "\n" + solution_line
  else:
    arranged_line = top_line + "\n" + bottom_line + "\n" + dash_line
  
  return arranged_line

test_module.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import pytest

from arithmetic_arranger import arithmetic_arranger

test_cases = [
    pytest.param(
        [['3801 - 2', '123 + 49']],
        '  3801      123\n'
        '-    2    +  49\n'
        '------    -----',
        'Expected different output when calling "arithmetic_arranger()" with ["3801 - 2", "123 + 49"]',
        id='test_two_problems_arrangement1'),
    pytest.param(
        [['1 + 2', '1 - 9380']],
        '  1         1\n'
        '+ 2    - 9380\n'
        '---    ------',
        'Expected different output when calling "arithmetic_arranger()" with ["1 + 2", "1 - 9380"]',
        id='test_two_problems_arrangement2'),
    pytest.param(
        [['3 + 855', '3801 - 2', '45 + 43', '123 + 49']],
        '    3      3801      45      123\n'
        '+ 855    -    2    + 43    +  49\n'
        '-----    ------    ----    -----',
        'Expected different output when calling "arithmetic_arranger()" with ["3 + 855", "3801 - 2", "45 + 43", "123 + 49"]',
        id='test_four_problems_arrangement'),
    pytest.param(
        [['11 + 4', '3801 - 2999', '1 + 2', '123 + 49', '1 - 9380']],
        '  11      3801      1      123         1\n'
        '+  4    - 2999    + 2    +  49    - 9380\n'
        '----    ------    ---    -----    ------',
        'Expected different output when calling "arithmetic_arranger()" with ["11 + 4", "3801 - 2999", "1 + 2", "123 + 49", "1 - 9380"]',
        id='test_five_problems_arrangement'),
    pytest.param(
        [['44 + 815', '909 - 2', '45 + 43', '123 + 49',
          '888 + 40', '653 + 87']],
        'Error: Too many problems.',
        'Expected calling "arithmetic_arranger()" with more than five problems to return "Error: Too many problems."',
        id='test_too_many_problems'),
    pytest.param(
        [['3 / 855', '3801 - 2', '45 + 43', '123 + 49']],
        "Error: Operator must be '+' or '-'.",
        '''Expected calling "arithmetic_arranger()" with a problem that uses the "/" operator to return "Error: Operator must be '+' or '-'."''',
        id='test_incorrect_operator'),
    pytest.param(
        [['24 + 85215', '3801 - 2', '45 + 43', '123 + 49']],
        'Error: Numbers cannot be more than four digits.',
        'Expected calling "arithmetic_arranger()" with a problem that has a number over 4 digits long to return "Error: Numbers cannot be more than four digits."',
        id='test_too_many_digits'),
    pytest.param(
        [['98 + 3g5', '3801 - 2', '45 + 43', '123 + 49']],
        'Error: Numbers must only contain digits.',
        'Expected calling "arithmetic_arranger()" with a problem that contains a letter character in the number to return "Error: Numbers must only contain digits."',
        id='test_only_digits'),
    pytest.param(
        [['3 + 855', '988 + 40'], True],
        '    3      988\n'
        '+ 855    +  40\n'
        '-----    -----\n'
        '  858     1028',
        'Expected solutions to be correctly displayed in output when calling "arithmetic_arranger()" with ["3 + 855", "988 + 40"] and a second argument of `True`.',
        id='test_two_problems_with_solutions'),
    pytest.param(
        [['32 - 698', '1 - 3801', '45 + 43', '123 + 49', '988 + 40'], True],
        '   32         1      45      123      988\n'
        '- 698    - 3801    + 43    +  49    +  40\n'
        '-----    ------    ----    -----    -----\n'
        ' -666     -3800      88      172     1028',
        'Expected solutions to be correctly displayed in output when calling "arithmetic_arranger()" with five arithmetic problems and a second argument of `True`.',
        id='test_five_problems_with_solutions'),
]


@pytest.mark.parametrize('arguments,expected_output,fail_message', test_cases)
def test_template(arguments, expected_output, fail_message):
    actual = arithmetic_arranger(*arguments)
    assert actual == expected_output, fail_message

Outline of Test Cases

Write a function named add_time that takes in two required parameters and one optional parameter:

  • a start time in the 12-hour clock format (ending in AM or PM)
  • a duration time that indicates the number of hours and minutes
  • (optional) a starting day of the week, case insensitive

  • The function should add the duration time to the start time and return the result.

    If the result will be the next day, it should show (next day) after the time. If the result will be more than one day later, it should show (n days later) after the time, where "n" is the number of days later.

    If the function is given the optional starting day of the week parameter, then the output should display the day of the week of the result. The day of the week in the output should appear after the time and before the number of days later.

    Code

    See my replit code to run against the test modules


    main.py

    1
    2
    3
    4
    5
    6
    7
    from time_calculator import add_time
    from unittest import main
    
    print(add_time("11:06 PM", "2:02"))
    
    # Run unit tests automatically
    main(module='test_module', exit=False)
    

    time_calculator.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    def add_time(start, duration, day_of_week=None):
        days = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
    
        # Convert to 24 hour time and integers
        start_hour, start_minute = start.split()[0].split(":")
        period = start.split()[1]
        if (period == "PM"):
            start_hour = int(start_hour) + 12
        else:
            start_hour = int(start_hour)
        start_minute = int(start_minute)
        # Get the duration of each hour and minute by splitting the duration
        duration_hour, duration_minute = duration.split(":")
        duration_hour = int(duration_hour)
        duration_minute = int(duration_minute)
    
        # Calculate initial ending time
        end_minute = start_minute + duration_minute
        end_hour = start_hour + duration_hour
        end_day = 0
    
        # Convert to proper number of days, hours, minutes
        end_hour = end_hour + (end_minute // 60)
        end_minute = end_minute % 60
        end_day = end_day + (end_hour // 24)
        end_hour = end_hour % 24
    
        # Convert hour back to 12 hour time
        if end_hour > 12:
            end_hour = end_hour - 12
            end_period = 'PM'
        elif end_hour == 12:
            end_period = 'PM'
        elif end_hour == 0:
            end_hour = 12
            end_period = 'AM'
        else:
            end_period = 'AM'
    
        # Format and return the new time
        new_time = "{}:{:02d} {}".format(end_hour, end_minute, end_period)
    
        # If needed, then calculate the ending day of the week
        if day_of_week:
            new_time += ", " + days[(days.index(day_of_week.lower()) + end_day) % 7].title()
    
        # If end_day > 0, then add the number of days
        if end_day > 0:
            if end_day == 1:
                new_time += " (next day)" #if its the next day
            else:
                new_time += " ({} days later)".format(end_day) #if more than one day later
    
        return new_time
    

    test_module.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    import unittest
    from time_calculator import add_time
    
    
    class UnitTests(unittest.TestCase):
    
        def test_same_period(self):
            actual = add_time("3:30 PM", "2:12")
            expected = "5:42 PM"
            self.assertEqual(actual, expected, 'Expected calling "add_time()" with "3:30 PM", "2:12" to return "5:42 PM"')
    
        def test_different_period(self):
            actual = add_time("11:55 AM", "3:12")
            expected = "3:07 PM"
            self.assertEqual(actual, expected, 'Expected calling "add_time()" with "11:55 AM", "3:12" to return "3:07 PM"')
    
        def test_next_day(self):
            actual = add_time("9:15 PM", "5:30")
            expected = "2:45 AM (next day)"
            self.assertEqual(actual, expected, 'Expected time to end with "(next day)" when it is the next day.')
    
        def test_period_change_at_twelve(self):
            actual = add_time("11:40 AM", "0:25")
            expected = "12:05 PM"
            self.assertEqual(actual, expected, 'Expected period to change from AM to PM at 12:00')
    
        def test_twenty_four(self):
            actual = add_time("2:59 AM", "24:00")
            expected = "2:59 AM (next day)"
            self.assertEqual(actual, expected, 'Expected calling "add_time()" with "2:59 AM", "24:00" to return "2:59 AM"')
    
        def test_two_days_later(self):
            actual = add_time("11:59 PM", "24:05")
            expected = "12:04 AM (2 days later)"
            self.assertEqual(actual, expected, 'Expected calling "add_time()" with "11:59 PM", "24:05" to return "12:04 AM (2 days later)"')
    
        def test_high_duration(self):
            actual = add_time("8:16 PM", "466:02")
            expected = "6:18 AM (20 days later)"
            self.assertEqual(actual, expected, 'Expected calling "add_time()" with "8:16 PM", "466:02" to return "6:18 AM (20 days later)"')
    
        def test_no_change(self):
            actual = add_time("5:01 AM", "0:00")
            expected = "5:01 AM"
            self.assertEqual(actual, expected, 'Expected adding 0:00 to return initial time.')
    
        def test_same_period_with_day(self):
            actual = add_time("3:30 PM", "2:12", "Monday")
            expected = "5:42 PM, Monday"
            self.assertEqual(actual, expected, 'Expected calling "add_time()" with "3:30 PM", "2:12", "Monday" to return "5:42 PM, Monday"')
    
        def test_twenty_four_with_day(self):
            actual = add_time("2:59 AM", "24:00", "saturDay")
            expected = "2:59 AM, Sunday (next day)"
            self.assertEqual(actual, expected, 'Expected calling "add_time()" with "2:59 AM", "24:00", "saturDay" to return "2:59 AM, Sunday (next day)"')
    
        def test_two_days_later_with_day(self):
            actual = add_time("11:59 PM", "24:05", "Wednesday")
            expected = "12:04 AM, Friday (2 days later)"
            self.assertEqual(actual, expected, 'Expected calling "add_time()" with "11:59 PM", "24:05", "Wednesday" to return "12:04 AM, Friday (2 days later)"')
    
        def test_high_duration_with_day(self):
            actual = add_time("8:16 PM", "466:02", "tuesday")
            expected = "6:18 AM, Monday (20 days later)"
            self.assertEqual(actual, expected, 'Expected calling "add_time()" with "8:16 PM", "466:02", "tuesday" to return "6:18 AM, Monday (20 days later)"')
    
    if __name__ == "__main__":
        unittest.main()
    

    Outline of Test Cases

    Complete the Category class in budget.py. It should be able to instantiate objects based on different budget categories like food, clothing, and entertainment. When objects are created, they are passed in the name of the category. The class should have an instance variable called ledger that is a list. The class should also contain the following methods:

  • A deposit method that accepts an amount and description. If no description is given, it should default to an empty string. The method should append an object to the ledger list in the form of {"amount": amount, "description": description}.
  • A withdraw method that is similar to the deposit method, but the amount passed in should be stored in the ledger as a negative number. If there are not enough funds, nothing should be added to the ledger. This method should return True if the withdrawal took place, and False otherwise.
  • A get_balance method that returns the current balance of the budget category based on the deposits and withdrawals that have occurred.
  • A transfer method that accepts an amount and another budget category as arguments. The method should add a withdrawal with the amount and the description "Transfer to [Destination Budget Category]". The method should then add a deposit to the other budget category with the amount and the description "Transfer from [Source Budget Category]". If there are not enough funds, nothing should be added to either ledgers. This method should return True if the transfer took place, and False otherwise.
  • A check_funds method that accepts an amount as an argument. It returns False if the amount is greater than the balance of the budget category and returns True otherwise. This method should be used by both the withdraw method and transfer method.

  • When the budget object is printed it should display:

  • A title line of 30 characters where the name of the category is centered in a line of * characters.
  • A list of the items in the ledger. Each line should show the description and amount. The first 23 characters of the description should be displayed, then the amount. The amount should be right aligned, contain two decimal places, and display a maximum of 7 characters.
  • A line displaying the category total.

  • The output should look like this:
    *************Food*************
    initial deposit        1000.00
    groceries               -10.15
    restaurant and more foo -15.89
    Transfer to Clothing    -50.00
    Total: 923.96
    Besides the Category class, create a function (outside of the class) called create_spend_chart that takes a list of categories as an argument. It should return a string that is a bar chart.
    The chart should show the percentage spent in each category passed in to the function. The percentage spent should be calculated only with withdrawals and not with deposits. Down the left side of the chart should be labels 0 - 100. The "bars" in the bar chart should be made out of the "o" character. The height of each bar should be rounded down to the nearest 10. The horizontal line below the bars should go two spaces past the final bar. Each category name should be written vertically below the bar. There should be a title at the top that says "Percentage spent by category".
    This function will be tested with up to four categories.
    Look at the example output below very closely and make sure the spacing of the output matches the example exactly.

    Percentage spent by category
    100|
     90|
     80|
     70|
     60| o
     50| o
     40| o
     30| o
     20| o  o
     10| o  o  o
      0| o  o  o
        ----------
         F  C  A
         o  l  u
         o  o  t
         d  t  o
            h
            i
            n
            g

    Code

    See my replit code to run against the test modules

    main.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import budget
    from budget import create_spend_chart
    from unittest import main
    
    food = budget.Category("Food")
    food.deposit(1000, "initial deposit")
    food.withdraw(10.15, "groceries")
    food.withdraw(15.89, "restaurant and more food for dessert")
    print(food.get_balance())
    clothing = budget.Category("Clothing")
    food.transfer(50, clothing)
    clothing.withdraw(25.55)
    clothing.withdraw(100)
    auto = budget.Category("Auto")
    auto.deposit(1000, "initial deposit")
    auto.withdraw(15)
    
    print(food)
    print(clothing)
    
    print(create_spend_chart([food, clothing, auto]))
    
    # Run unit tests automatically
    main(module='test_module', exit=False)
    

    budget.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    class Category:
        def __init__(user, u):
            user.category = u
            user.ledger = []
    #function for the deposit of cash
        def deposit(user, amount, description=''):
            user.ledger.append({'amount': amount, 'description': description})
          
    #function for the withdrawal of cash
        def withdraw(user, amount, description=''):
            if user.check_funds(amount): #if there is enough cash then
                user.ledger.append({'amount': -amount, 'description': description}) #make the withdrawl and remove the amount
                return True
            else: #else return false
                return False
    
    #function for the balance total using the ledger amount
        def get_balance(user):
            return sum([x.get('amount') for x in user.ledger]) 
    
    #function for the transfer of cash 
        def transfer(user, amount, cat):
            if user.check_funds(amount): #if the person has enough money
                user.withdraw(amount, f'Transfer to {cat.category}') #make the withdrawal and send a message to confirming the transfer
                cat.deposit(amount, f'Transfer from {user.category}') #and depoist the money and send a message to the receiver
                return True
            else:
                return False
    
    #function to check the total balance in persons account
        def check_funds(user, amount):
            return user.get_balance() >= amount
    
    #function to give the bills descriptions and total amount
        def __str__(user):
            bill = user.category.center(30, '*') + '\n'
            for i in user.ledger:
                bill += f'{i.get("description")[:23]:23}' + f'{i.get("amount"):7.2f}' + '\n'
    
            bill += f'Total: {user.get_balance():.2f}'
            return bill
    
    #function to show the different items costs and display it into a receipt layout
    def create_spend_chart(categories):
        receipt = 'Percentage spent by category\n'
        withdrawals = [
          -sum([i.get('amount')
          for i in cat.ledger 
            if i.get('amount') < 0])
              for cat in categories]
        percent_withdrawal = [round(i / sum(withdrawals) * 100) for i in withdrawals]
        names = [cat.category.lower().capitalize() for cat in categories]
        
        for i in range(100, -10, -10):
            receipt += str(i).rjust(3) + "| "
            
            for percent in percent_withdrawal:
                receipt += "o  " if percent >= i else "   "
            receipt += "\n"
    
        receipt += ' ' * 4 + '-' * (2 * (len(categories) + 1) + 2) 
        max_len = len(max(names, key=len))
        names = [i.ljust(max_len) for i in names]
        for i in range(max_len):
            receipt += '\n     '
            for name in names:
                receipt += name[i] + '  '
    
        return receipt
    

    test_module.py

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    import unittest
    import budget
    from budget import create_spend_chart
    
    
    class UnitTests(unittest.TestCase):
        maxDiff = None
        def setUp(self):
            self.food = budget.Category("Food")
            self.entertainment = budget.Category("Entertainment")
            self.business = budget.Category("Business")
    
        def test_deposit(self):
            self.food.deposit(900, "deposit")
            actual = self.food.ledger[0]
            expected = {"amount": 900, "description": "deposit"}
            self.assertEqual(actual, expected, 'Expected `deposit` method to create a specific object in the ledger instance variable.')
    
        def test_deposit_no_description(self):
            self.food.deposit(45.56)
            actual = self.food.ledger[0]
            expected = {"amount": 45.56, "description": ""}
            self.assertEqual(actual, expected, 'Expected calling `deposit` method with no description to create a blank description.')
    
        def test_withdraw(self):
            self.food.deposit(900, "deposit")
            self.food.withdraw(45.67, "milk, cereal, eggs, bacon, bread")
            actual = self.food.ledger[1]
            expected = {"amount": -45.67, "description": "milk, cereal, eggs, bacon, bread"}
            self.assertEqual(actual, expected, 'Expected `withdraw` method to create a specific object in the ledger instance variable.')
    
        def test_withdraw_no_description(self):
            self.food.deposit(900, "deposit")
            good_withdraw = self.food.withdraw(45.67)
            actual = self.food.ledger[1]
            expected = {"amount": -45.67, "description": ""}
            self.assertEqual(actual, expected, 'Expected `withdraw` method with no description to create a blank description.')
            self.assertEqual(good_withdraw, True, 'Expected `withdraw` method to return `True`.')
    
        def test_get_balance(self):
            self.food.deposit(900, "deposit")
            self.food.withdraw(45.67, "milk, cereal, eggs, bacon, bread")
            actual = self.food.get_balance()
            expected = 854.33
            self.assertEqual(actual, expected, 'Expected balance to be 854.33')
    
        def test_transfer(self):
            self.food.deposit(900, "deposit")
            self.food.withdraw(45.67, "milk, cereal, eggs, bacon, bread")
            transfer_amount = 20
            food_balance_before = self.food.get_balance()
            entertainment_balance_before = self.entertainment.get_balance()
            good_transfer = self.food.transfer(transfer_amount, self.entertainment)
            food_balance_after = self.food.get_balance()
            entertainment_balance_after = self.entertainment.get_balance()
            actual = self.food.ledger[2]
            expected = {"amount": -transfer_amount, "description": "Transfer to Entertainment"}
            self.assertEqual(actual, expected, 'Expected `transfer` method to create a specific ledger item in food object.')
            self.assertEqual(good_transfer, True, 'Expected `transfer` method to return `True`.')
            self.assertEqual(food_balance_before - food_balance_after, transfer_amount, 'Expected `transfer` method to reduce balance in food object.')
            self.assertEqual(entertainment_balance_after - entertainment_balance_before, transfer_amount, 'Expected `transfer` method to increase balance in entertainment object.')
            actual = self.entertainment.ledger[0]
            expected = {"amount": transfer_amount, "description": "Transfer from Food"}
            self.assertEqual(actual, expected, 'Expected `transfer` method to create a specific ledger item in entertainment object.')
    
        def test_check_funds(self):
            self.food.deposit(10, "deposit")
            actual = self.food.check_funds(20)
            expected = False
            self.assertEqual(actual, expected, 'Expected `check_funds` method to be False')
            actual = self.food.check_funds(10)
            expected = True
            self.assertEqual(actual, expected, 'Expected `check_funds` method to be True')
    
        def test_withdraw_no_funds(self):
            self.food.deposit(100, "deposit")
            good_withdraw = self.food.withdraw(100.10)
            self.assertEqual(good_withdraw, False, 'Expected `withdraw` method to return `False`.')
    
        def test_transfer_no_funds(self):
            self.food.deposit(100, "deposit")
            good_transfer = self.food.transfer(200, self.entertainment)
            self.assertEqual(good_transfer, False, 'Expected `transfer` method to return `False`.')
    
        def test_to_string(self):
            self.food.deposit(900, "deposit")
            self.food.withdraw(45.67, "milk, cereal, eggs, bacon, bread")
            self.food.transfer(20, self.entertainment)
            actual = str(self.food)
            expected = f"*************Food*************\ndeposit                 900.00\nmilk, cereal, eggs, bac -45.67\nTransfer to Entertainme -20.00\nTotal: 834.33"
            self.assertEqual(actual, expected, 'Expected different string representation of object.')
    
        def test_create_spend_chart(self):
            self.food.deposit(900, "deposit")
            self.entertainment.deposit(900, "deposit")
            self.business.deposit(900, "deposit")
            self.food.withdraw(105.55)
            self.entertainment.withdraw(33.40)
            self.business.withdraw(10.99)
            actual = create_spend_chart([self.business, self.food, self.entertainment])
            expected = "Percentage spent by category\n100|          \n 90|          \n 80|          \n 70|    o     \n 60|    o     \n 50|    o     \n 40|    o     \n 30|    o     \n 20|    o  o  \n 10|    o  o  \n  0| o  o  o  \n    ----------\n     B  F  E  \n     u  o  n  \n     s  o  t  \n     i  d  e  \n     n     r  \n     e     t  \n     s     a  \n     s     i  \n           n  \n           m  \n           e  \n           n  \n           t  "
            self.assertEqual(actual, expected, 'Expected different chart representation. Check that all spacing is exact.')
    
    if __name__ == "__main__":
        unittest.main()
    

    Outline of Test Cases

    In this project you will use object oriented programming to create a Rectangle class and a Square class. The Square class should be a subclass of Rectangle and inherit methods and attributes.

    Rectangle class
    When a Rectangle object is created, it should be initialized with width and height attributes. The class should also contain the following methods:

  • set_width
  • set_height
  • get_area: Returns area (width * height)
  • get_perimeter: Returns perimeter (2 * width + 2 * height)
  • get_diagonal: Returns diagonal ((width ** 2 + height ** 2) ** .5)
  • get_picture: Returns a string that represents the shape using lines of "*". The number of lines should be equal to the height and the number of "*" in each line should be equal to the width. There should be a new line (\n) at the end of each line. If the width or height is larger than 50, this should return the string: "Too big for picture.".
  • get_amount_inside: Takes another shape (square or rectangle) as an argument. Returns the number of times the passed in shape could fit inside the shape (with no rotations). For instance, a rectangle with a width of 4 and a height of 8 could fit in two squares with sides of 4.
  • Additionally, if an instance of a Rectangle is represented as a string, it should look like: Rectangle(width=5, height=10)

    Square class
    The Square class should be a subclass of Rectangle. When a Square object is created, a single side length is passed in. The __init__ method should store the side length in both the width and height attributes from the Rectangle class.
    The Square class should be able to access the Rectangle class methods but should also contain a set_side method. If an instance of a Square is represented as a string, it should look like: Square(side=9)

    Additionally, the set_width and set_height methods on the Square class should set both the width and height.

    Code

    See my replit code to run against the test modules

    main.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import shape_calculator
    from unittest import main
    
    rect = shape_calculator.Rectangle(5, 10)
    print(rect.get_area())
    rect.set_width(3)
    print(rect.get_perimeter())
    print(rect)
    
    sq = shape_calculator.Square(9)
    print(sq.get_area())
    sq.set_side(4)
    print(sq.get_diagonal())
    print(sq)
    
    
    # Run unit tests automatically
    main(module='test_module', exit=False)
    

    shape_calculator.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    class Rectangle:
    #get the initial data
        def __init__(x, w, h):
            x.width = w
            x.height = h
    #function to return the width and height
        def __str__(x):
            return f'Rectangle(width={x.width}, height={x.height})'
    #set the width
        def set_width(x, w):
            x.width = w
    #set the height
        def set_height(x, h):
            x.height = h
    #function to return the area (width * height)
        def get_area(x):
            return x.width * x.height
    #function to return the perimeter (2 * width + 2 * height)
        def get_perimeter(x):
            return 2 * (x.width + x.height)
    #function to return the diagonal line ((width ** 2 + height ** 2) ** .5)
        def get_diagonal(x):
            return (x.width ** 2 + x.height ** 2) ** 0.5
    #function to returns a string that represents the shape using lines of "*"
        def get_picture(x):
            if x.width > 50 or x.height > 50:
                return 'Too big for picture.'
    
            pic = '*' * x.width + '\n'
            pic = pic * x.height
            return pic
    #function to returns the number of times the passed in shape could fit inside the shape (with no rotations)
        def get_amount_inside(x, ob):
            return x.get_area() // ob.get_area()
    
    
    class Square(Rectangle):
        def __init__(x, s):
            super().__init__(s, s)
    #function to set the number of sides drawn
        def set_side(x, s):
            x.width = s
            x.height = s
    #function to say what the shape is and the number of sides    
        def __str__(x):
            return f'Square(side={x.width})'
    

    test_module.py

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    import unittest
    import shape_calculator
    
    
    class UnitTests(unittest.TestCase):
        maxDiff = None
        def setUp(self):
            self.rect = shape_calculator.Rectangle(3, 6)
            self.sq = shape_calculator.Square(5)
    
        def test_subclass(self):
            actual = issubclass(shape_calculator.Square, shape_calculator.Rectangle)
            expected = True
            self.assertEqual(actual, expected, 'Expected Square class to be a subclass of the Rectangle class.')
    
        def test_distinct_classes(self):
            actual = shape_calculator.Square is not shape_calculator.Rectangle
            expected = True
            self.assertEqual(actual, expected, 'Expected Square class to be a distinct class from the Rectangle class.')
    
        def test_square_is_square_and_rectangle(self):
            actual = isinstance(self.sq, shape_calculator.Square) and isinstance(self.sq, shape_calculator.Rectangle)
            expected = True
            self.assertEqual(actual, expected, 'Expected square object to be an instance of the Square class and the Rectangle class.')
    
        def test_rectangle_string(self):
            actual = str(self.rect)
            expected = "Rectangle(width=3, height=6)"
            self.assertEqual(actual, expected, 'Expected string representation of rectangle to be "Rectangle(width=3, height=6)"')
    
        def test_square_string(self):
            actual = str(self.sq)
            expected = "Square(side=5)"
            self.assertEqual(actual, expected, 'Expected string representation of square to be "Square(side=5)"')
    
        def test_area(self):
            actual = self.rect.get_area()
            expected = 18
            self.assertEqual(actual, expected, 'Expected area of rectangle to be 18')
            actual = self.sq.get_area()
            expected = 25
            self.assertEqual(actual, expected, 'Expected area of square to be 25')
            
    
        def test_perimeter(self):
            actual = self.rect.get_perimeter()
            expected = 18
            self.assertEqual(actual, expected, 'Expected perimeter of rectangle to be 18')
            actual = self.sq.get_perimeter()
            expected = 20
            self.assertEqual(actual, expected, 'Expected perimeter of square to be 20')
    
        def test_diagonal(self):
            actual = self.rect.get_diagonal()
            expected = 6.708203932499369
            self.assertEqual(actual, expected, 'Expected diagonal of rectangle to be 6.708203932499369')
            actual = self.sq.get_diagonal()
            expected = 7.0710678118654755
            self.assertEqual(actual, expected, 'Expected diagonal of square to be 7.0710678118654755')
    
        def test_set_attributes(self):
            self.rect.set_width(7)
            self.rect.set_height(8)
            self.sq.set_side(2)
            actual = str(self.rect)
            expected = "Rectangle(width=7, height=8)"
            self.assertEqual(actual, expected, 'Expected string representation of rectangle after setting new values to be "Rectangle(width=7, height=8)"')
            actual = str(self.sq)
            expected = "Square(side=2)"
            self.assertEqual(actual, expected, 'Expected string representation of square after setting new values to be "Square(side=2)"')
            self.sq.set_width(4)
            actual = str(self.sq)
            expected = "Square(side=4)"
            self.assertEqual(actual, expected, 'Expected string representation of square after setting width to be "Square(side=4)"')
    
        def test_rectangle_picture(self):
            self.rect.set_width(7)
            self.rect.set_height(3)
            actual = self.rect.get_picture()
            expected = "*******\n*******\n*******\n"
            self.assertEqual(actual, expected, 'Expected rectangle picture to be different.')     
    
        def test_square_picture(self):
            self.sq.set_side(2)
            actual = self.sq.get_picture()
            expected = "**\n**\n"
            self.assertEqual(actual, expected, 'Expected square picture to be different.')   
    
        def test_big_picture(self):
            self.rect.set_width(51)
            self.rect.set_height(3)
            actual = self.rect.get_picture()
            expected = "Too big for picture."
            self.assertEqual(actual, expected, 'Expected message: "Too big for picture."')
    
        def test_get_amount_inside(self):
            self.rect.set_height(10)
            self.rect.set_width(15)
            actual = self.rect.get_amount_inside(self.sq)
            expected = 6
            self.assertEqual(actual, expected, 'Expected `get_amount_inside` to return 6.')
    
        def test_get_amount_inside_two_rectangles(self):
            rect2 = shape_calculator.Rectangle(4, 8)
            actual = rect2.get_amount_inside(self.rect)
            expected = 1
            self.assertEqual(actual, expected, 'Expected `get_amount_inside` to return 1.')
    
        def test_get_amount_inside_none(self):
            rect2 = shape_calculator.Rectangle(2, 3)
            actual = rect2.get_amount_inside(self.rect)
            expected = 0
            self.assertEqual(actual, expected, 'Expected `get_amount_inside` to return 0.')
            
    if __name__ == "__main__":
        unittest.main()
    

    Outline of Test Cases

    For this project, you will write a program to determine the approximate probability of drawing certain balls randomly from a hat.
    Create a Hat class, which should take a variable number of arguments that specify the number of balls of each color that are in the hat.
    A hat will always be created with at least one ball. The arguments passed into the hat object upon creation should be converted to a contents instance variable. contents should be a list of strings containing one item for each ball in the hat. Each item in the list should be a color name representing a single ball of that color.
    The Hat class should have a draw method that accepts an argument indicating the number of balls to draw from the hat. This method should remove balls at random from contents and return those balls as a list of strings. The balls should not go back into the hat during the draw, similar to an urn experiment without replacement. If the number of balls to draw exceeds the available quantity, return all the balls.

    Create an experiment function in prob_calculator.py, which should accept the following arguments:

  • hat: A hat object containing balls that should be copied inside the function.
  • expected_balls: An object indicating the exact group of balls to attempt to draw from the hat for the experiment.
  • num_balls_drawn: The number of balls to draw out of the hat in each experiment.
  • num_experiments: The number of experiments to perform. (The more experiments performed, the more accurate the approximate probability will be.)

  • The experiment function should return a probability.

    You will need to perform N experiments, count how many times M we get at a certain amount of balls, and estimate the probability as M/N. Each experiment consists of starting with a hat containing the specified balls, drawing a number of balls, and checking if we got the balls we were attempting to draw.

    Code

    See my replit code to run against the test modules

    main.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    import prob_calculator
    from unittest import main
    
    prob_calculator.random.seed(95)
    hat = prob_calculator.Hat(blue=4, red=2, green=6)
    probability = prob_calculator.experiment(
        hat=hat,
        expected_balls={"blue": 2,
                        "red": 1},
        num_balls_drawn=4,
        num_experiments=3000)
    print("Probability:", probability)
    
    # Run unit tests automatically
    main(module='test_module', exit=False)
    

    prob_calculator.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    import copy
    import random
    
    class Hat:
      def __init__(x,**all_item):
        x.contents=[]
        for key,value in all_item.items():
            for itr in range(value):
              x.contents.append(key)
      
      # Function to get random n number of hats from contents
      def draw(x,amount):
          draw_list = []
          if amount >= len(x.contents):
              return x.contents
          for i in range(amount):
              name=x.contents.pop(random.randrange(len(x.contents)))
              draw_list.append(name)
          return draw_list
    
      # Function to get the probability
    def experiment(hat, expected_balls, num_balls_drawn, num_experiments):
        final_count=0
        for _ in range(num_experiments):
          copyhat = copy.deepcopy(hat)
          temp_list = copyhat.draw(num_balls_drawn)
          success=True
          for key,value in expected_balls.items():
            if temp_list.count(key) < value:
              success=False
              break
          if success:
            final_count+=1
        return final_count/num_experiments #return the probability
    

    test_module.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    import unittest
    import prob_calculator
    
    prob_calculator.random.seed(95)
    class UnitTests(unittest.TestCase):
        maxDiff = None
        def test_hat_class_contents(self):
            hat = prob_calculator.Hat(red=3,blue=2)
            actual = hat.contents
            expected = ["red","red","red","blue","blue"]
            self.assertEqual(actual, expected, 'Expected creation of hat object to add correct contents.')
    
        def test_hat_draw(self):
            hat = prob_calculator.Hat(red=5,blue=2)
            actual = hat.draw(2)
            expected = ['blue', 'red']
            self.assertEqual(actual, expected, 'Expected hat draw to return two random items from hat contents.')
            actual = len(hat.contents)
            expected = 5
            self.assertEqual(actual, expected, 'Expected hat draw to reduce number of items in contents.')
    
        def test_prob_experiment(self):
            hat = prob_calculator.Hat(blue=3,red=2,green=6)
            probability = prob_calculator.experiment(hat=hat, expected_balls={"blue":2,"green":1}, num_balls_drawn=4, num_experiments=1000)
            actual = probability
            expected = 0.272
            self.assertAlmostEqual(actual, expected, delta = 0.01, msg = 'Expected experiment method to return a different probability.')
            hat = prob_calculator.Hat(yellow=5,red=1,green=3,blue=9,test=1)
            probability = prob_calculator.experiment(hat=hat, expected_balls={"yellow":2,"blue":3,"test":1}, num_balls_drawn=20, num_experiments=100)
            actual = probability
            expected = 1.0
            self.assertAlmostEqual(actual, expected, delta = 0.01, msg = 'Expected experiment method to return a different probability.')
    
    
    if __name__ == "__main__":
        unittest.main()
    

    Outline of Test Cases

    Create a function named calculate() in mean_var_std.py that uses Numpy to output the mean, variance, standard deviation, max, min, and sum of the rows, columns, and elements in a 3 x 3 matrix.

    The input of the function should be a list containing 9 digits. The function should convert the list into a 3 x 3 Numpy array, and then return a dictionary containing the mean, variance, standard deviation, max, min, and sum along both axes and for the flattened matrix.

    The returned dictionary should follow this format:
    {
    'mean': [axis1, axis2, flattened],
    'variance': [axis1, axis2, flattened],
    'standard deviation': [axis1, axis2, flattened],
    'max': [axis1, axis2, flattened],
    'min': [axis1, axis2, flattened],
    'sum': [axis1, axis2, flattened]
    }
    If a list containing less than 9 elements is passed into the function, it should raise a ValueError exception with the message: "List must contain nine numbers." The values in the returned dictionary should be lists and not Numpy arrays.

    Code

    See my replit code to run against the test modules

    main.py

     1
    2
    3
    4
    5
    6
    7
    import mean_var_std
    from unittest import main
    
    print(mean_var_std.calculate([0,1,2,3,4,5,6,7,8]))
    
    # Run unit tests automatically
    main(module='test_module', exit=False)
    

    mean_var_std.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    import numpy as np
    
    def calculate(list):
        if len(list) != 9:
            raise ValueError('List must contain nine numbers.')
        else:
            matrix = np.array(list).reshape(3, 3)
    #returned the dictionary items:
    #The flatten() function is used to get a copy of an given array collapsed into one dimension.
        mean = [(matrix.mean(axis=0).tolist()), (matrix.mean(axis=1).tolist()),
                (matrix.flatten().mean())]
    
        var = [(matrix.var(axis=0).tolist()), (matrix.var(axis=1).tolist()),
               (matrix.flatten().var())]
    
        std = [(matrix.std(axis=0).tolist()), (matrix.std(axis=1).tolist()),
               (matrix.flatten().std())]
    
        max = [(matrix.max(axis=0).tolist()), (matrix.max(axis=1).tolist()),
               (matrix.flatten().max())]
    
        min = [(matrix.min(axis=0).tolist()), (matrix.min(axis=1).tolist()),
               (matrix.flatten().min())]
    
        sum = [(matrix.sum(axis=0).tolist()), (matrix.sum(axis=1).tolist()),
               (matrix.flatten().sum())]
    
        calculations = {
            "mean": mean,
            "variance": var,
            "standard deviation": std,
            "max": max,
            "min": min,
            "sum": sum,
        }
        return calculations
    

    test_module.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import unittest
    import mean_var_std
    
    
    # the test case
    class UnitTests(unittest.TestCase):
        def test_calculate(self):
            actual = mean_var_std.calculate([2,6,2,8,4,0,1,5,7])
            expected = {'mean': [[3.6666666666666665, 5.0, 3.0], [3.3333333333333335, 4.0, 4.333333333333333], 3.888888888888889], 'variance': [[9.555555555555557, 0.6666666666666666, 8.666666666666666], [3.555555555555556, 10.666666666666666, 6.222222222222221], 6.987654320987654], 'standard deviation': [[3.091206165165235, 0.816496580927726, 2.943920288775949], [1.8856180831641267, 3.265986323710904, 2.494438257849294], 2.6434171674156266], 'max': [[8, 6, 7], [6, 8, 7], 8], 'min': [[1, 4, 0], [2, 0, 1], 0], 'sum': [[11, 15, 9], [10, 12, 13], 35]}
            self.assertAlmostEqual(actual, expected, "Expected different output when calling 'calculate()' with '[2,6,2,8,4,0,1,5,7]'")
    
        def test_calculate2(self):
            actual = mean_var_std.calculate([9,1,5,3,3,3,2,9,0])
            expected = {'mean': [[4.666666666666667, 4.333333333333333, 2.6666666666666665], [5.0, 3.0, 3.6666666666666665], 3.888888888888889], 'variance': [[9.555555555555555, 11.555555555555557, 4.222222222222222], [10.666666666666666, 0.0, 14.888888888888891], 9.209876543209875], 'standard deviation': [[3.0912061651652345, 3.39934634239519, 2.0548046676563256], [3.265986323710904, 0.0, 3.8586123009300755], 3.0347778408328137], 'max': [[9, 9, 5], [9, 3, 9], 9], 'min': [[2, 1, 0], [1, 3, 0], 0], 'sum': [[14, 13, 8], [15, 9, 11], 35]}
            self.assertAlmostEqual(actual, expected, "Expected different output when calling 'calculate()' with '[9,1,5,3,3,3,2,9,0]'")
        
        def test_calculate_with_few_digits(self):
            self.assertRaisesRegex(ValueError, "List must contain nine numbers.", mean_var_std.calculate, [2,6,2,8,4,0,1,])
    
    if __name__ == "__main__":
        unittest.main()
    

    Outline of Test Cases

    Analyze demographic data using Pandas, use the dataset of demographic data that was extracted from the 1994 Census database.

    You must use Pandas to answer the following questions:

  • How many people of each race are represented in this dataset? This should be a Pandas series with race names as the index labels. (race column)
  • What is the average age of men?
  • What is the percentage of people who have a Bachelor's degree?
  • What percentage of people with advanced education (Bachelors, Masters, or Doctorate) make more than 50K?
  • What percentage of people without advanced education make more than 50K?
  • What is the minimum number of hours a person works per week?
  • What percentage of the people who work the minimum number of hours per week have a salary of more than 50K?
  • What country has the highest percentage of people that earn >50K and what is that percentage?
  • Identify the most popular occupation for those who earn >50K in India.
  • Code

    See my replit code to run against the test modules

    main.py

    1
    2
    3
    4
    5
    6
    7
    8
    import demographic_data_analyzer
    from unittest import main
    
    # Test your function by calling it here
    demographic_data_analyzer.calculate_demographic_data()
    
    # Run unit tests automatically
    main(module='test_module', exit=False)
    

    demographic_data_analyzer.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    import pandas as pd
    
    def calculate_demographic_data(print_data=True):
        # Read data from file
        df = pd.read_csv('adult.data.csv')
    
        # How many of each race are represented in this dataset? This should be a Pandas series with race names as the index labels.
        race_count = df['race'].value_counts()
    
        # What is the average age of men?
        average_age_men = round(df[df['sex'] == 'Male']['age'].mean(), 1)
    
        # What is the percentage of people who have a Bachelor's degree?
        percentage_bachelors = round(df[df['education'] == 'Bachelors'].shape[0] / df.shape[0] * 100, 1)
    
        # What percentage of people with advanced education (`Bachelors`, `Masters`, or `Doctorate`) make more than 50K?
        # What percentage of people without advanced education make more than 50K?
        q1 = df['education'].isin(['Bachelors', 'Masters', 'Doctorate'])
        q2 = df['salary'] == '>50K'
    
        higher_education_rich = round((q1 & q2).sum() / q1.sum() * 100, 1)
        lower_education_rich = round((~q1 & q2).sum() / (~q1).sum() * 100, 1)
    
        # What is the minimum number of hours a person works per week (hours-per-week feature)?
        min_work_hours = df['hours-per-week'].min()
    
        # What percentage of the people who work the minimum number of hours per week have a salary of >50K?
        q1 = df['hours-per-week'] == min_work_hours
    
        rich_percentage = round((q1 & q2).sum() / q1.sum() * 100, 1)
    
        # What country has the highest percentage of people that earn >50K?
        p = (df[q2]['native-country'].value_counts() \
                                    / df['native-country'].value_counts() * 100).sort_values(ascending=False)
    
        highest_earning_country = p.index[0]
        highest_earning_country_percentage = round(p.iloc[0], 1)
    
        # Identify the most popular occupation for those who earn >50K in India.
        top_IN_occupation = df[(df['native-country'] == 'India') & q2] \
                              ['occupation'].value_counts().index[0]
    
        # DO NOT MODIFY BELOW THIS LINE
    
        if print_data:
            print("Number of each race:\n", race_count) 
            print("Average age of men:", average_age_men)
            print(f"Percentage with Bachelors degrees: {percentage_bachelors}%")
            print(f"Percentage with higher education that earn >50K: {higher_education_rich}%")
            print(f"Percentage without higher education that earn >50K: {lower_education_rich}%")
            print(f"Min work time: {min_work_hours} hours/week")
            print(f"Percentage of rich among those who work fewest hours: {rich_percentage}%")
            print("Country with highest percentage of rich:", highest_earning_country)
            print(f"Highest percentage of rich people in country: {highest_earning_country_percentage}%")
            print("Top occupations in India:", top_IN_occupation)
    
        return {
            'race_count': race_count,
            'average_age_men': average_age_men,
            'percentage_bachelors': percentage_bachelors,
            'higher_education_rich': higher_education_rich,
            'lower_education_rich': lower_education_rich,
            'min_work_hours': min_work_hours,
            'rich_percentage': rich_percentage,
            'highest_earning_country': highest_earning_country,
            'highest_earning_country_percentage':
            highest_earning_country_percentage,
            'top_IN_occupation': top_IN_occupation
        }
    

    test_module.py

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    import unittest
    import demographic_data_analyzer
    
    class DemographicAnalyzerTestCase(unittest.TestCase):
        def setUp(self):
            self.data = demographic_data_analyzer.calculate_demographic_data(print_data = False)
    
        def test_race_count(self):
            actual = self.data['race_count'].tolist()
            expected = [27816, 3124, 1039, 311, 271]
            self.assertAlmostEqual(actual, expected, msg="Expected race count values to be [27816, 3124, 1039, 311, 271]")
        
        def test_average_age_men(self):
            actual = self.data['average_age_men']
            expected = 39.4
            self.assertAlmostEqual(actual, expected, msg="Expected different value for average age of men.")
    
        def test_percentage_bachelors(self):
            actual = self.data['percentage_bachelors']
            expected = 16.4 
            self.assertAlmostEqual(actual, expected, msg="Expected different value for percentage with Bachelors degrees.")
    
        def test_higher_education_rich(self):
            actual = self.data['higher_education_rich']
            expected = 46.5
            self.assertAlmostEqual(actual, expected, msg="Expected different value for percentage with higher education that earn >50K.")
      
        def test_lower_education_rich(self):
            actual = self.data['lower_education_rich']
            expected = 17.4
            self.assertAlmostEqual(actual, expected, msg="Expected different value for percentage without higher education that earn >50K.")
    
        def test_min_work_hours(self):
            actual = self.data['min_work_hours']
            expected = 1
            self.assertAlmostEqual(actual, expected, msg="Expected different value for minimum work hours.")     
    
        def test_rich_percentage(self):
            actual = self.data['rich_percentage']
            expected = 10
            self.assertAlmostEqual(actual, expected, msg="Expected different value for percentage of rich among those who work fewest hours.")   
    
        def test_highest_earning_country(self):
            actual = self.data['highest_earning_country']
            expected = 'Iran'
            self.assertEqual(actual, expected, "Expected different value for highest earning country.")   
    
        def test_highest_earning_country_percentage(self):
            actual = self.data['highest_earning_country_percentage']
            expected = 41.9
            self.assertAlmostEqual(actual, expected, msg="Expected different value for highest earning country percentage.")   
    
        def test_top_IN_occupation(self):
            actual = self.data['top_IN_occupation']
            expected = 'Prof-specialty'
            self.assertEqual(actual, expected, "Expected different value for top occupations in India.")      
    
    if __name__ == "__main__":
        unittest.main()