When something fails, read the traceback from the bottom: file, line, exception type, message. Then print the inputs, then add a test that fails the same way.
Goal
Cause a ValueError, read it, fix the call, and lock the rule in a test.
Read the traceback
def line_total(units, price):
if units < 0 or price < 0:
raise ValueError("units and price must be >= 0")
return round(units * price * 1.16, 2)
print(line_total(2, 10))Now the failing call:
def line_total(units, price):
if units < 0 or price < 0:
raise ValueError("units and price must be >= 0")
return round(units * price * 1.16, 2)
try:
print(line_total(-2, 10))
except ValueError as err:
print(type(err).__name__, err)Print the inputs
def city_label(city):
print("debug city=", repr(city))
return str(city or "").strip().title()
print(city_label(" nairobi "))Remove the debug print once you see repr(city) — leftover debug noise is a bug of its own.
Then a test
import unittest
def line_total(units, price):
if units < 0 or price < 0:
raise ValueError("units and price must be >= 0")
return round(units * price * 1.16, 2)
class PriceTests(unittest.TestCase):
def test_negative(self):
with self.assertRaises(ValueError):
line_total(-2, 10)
suite = unittest.defaultTestLoader.loadTestsFromTestCase(PriceTests)
result = unittest.TextTestRunner(verbosity=2).run(suite)
print("ok" if result.wasSuccessful() else "failed")Pitfall
There is no interactive pdb prompt in this tab. print + traceback + a failing test is the loop.