diff --git a/sum23/lecture_materials/14_Comprehensions/lec_14_comprehensions_notes.ipynb b/sum23/lecture_materials/14_Comprehensions/lec_14_comprehensions_notes.ipynb index 1c61d62f8fbcf18e6377ec24ffc6d22dfc5a64ef..b4dd87dd4542c686a35c4fe0a2e454b982e7c542 100644 --- a/sum23/lecture_materials/14_Comprehensions/lec_14_comprehensions_notes.ipynb +++ b/sum23/lecture_materials/14_Comprehensions/lec_14_comprehensions_notes.ipynb @@ -734,6 +734,9 @@ "\n", "for tuple_item in scores_dict.items():\n", " print(tuple_item)\n", + " key = tuple_item[0]\n", + " val = tuple_item[1]\n", + " print(key,val)\n", " \n", "print(\"--------------------\")\n", "\n", @@ -796,14 +799,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Original: {'Nov': 28, 'Dec': 20, 'Jan': 10, 'Feb': 14}\n", + "New dict: {'Nov': -2.2222222222222223, 'Dec': -6.666666666666667, 'Jan': -12.222222222222223, 'Feb': -10.0}\n" + ] + } + ], "source": [ "madison_fahrenheit = {'Nov': 28,'Dec': 20, 'Jan': 10,'Feb': 14}\n", "print(\"Original:\", madison_fahrenheit)\n", "\n", - "madison_celsius = {key: ??? \\\n", + "madison_celsius = {key: 5 / 9 * (val - 32) \\\n", " for key, val in madison_fahrenheit.items()}\n", "print(\"New dict:\", madison_celsius)" ] @@ -817,14 +829,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Original: {'Bob': '32', 'Cindy': '45', 'Alice': '39', 'Unknown': 'None'}\n", + "New dict: {'Bob': 32, 'Cindy': 45, 'Alice': 39, 'Unknown': None}\n" + ] + } + ], "source": [ "scores_dict = {\"Bob\": \"32\", \"Cindy\" : \"45\", \"Alice\": \"39\", \"Unknown\": \"None\"}\n", "print(\"Original:\", scores_dict)\n", "\n", - "updated_scores_dict = {???}\n", + "# updated_scores_dict = {???}\n", " \n", "# # step 1: add for statement\n", "# updated_scores_dict = { ??? for key, val in scores_dict.items() ???}\n", @@ -833,8 +854,8 @@ "# updated_scores_dict = { ??? if val.isdigit() else ??? for key, val in scores_dict.items()}\n", "\n", "# # step 3: fill in \"if\" and \"else\" values\n", - "# updated_scores_dict = {key: int(val) if val.isdigit() else None \\\n", - "# for key, val in scores_dict.items()}\n", + "updated_scores_dict = {key: int(val) if val.isdigit() else None \\\n", + " for key, val in scores_dict.items()}\n", "\n", "print(\"New dict:\", updated_scores_dict)" ] @@ -848,9 +869,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'Bob': 83, 'Cindy': 87, 'Alice': 90, 'Meena': 93}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "scores_dict = {\"Bob\": [18, 72, 61, 5, 83], \n", " \"Cindy\" : [27, 11, 55, 73, 87], \n", diff --git a/sum23/lecture_materials/15_Errors/lec_15_error_handling_notes.ipynb b/sum23/lecture_materials/15_Errors/lec_15_error_handling_notes.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..7713f92db3f117a6bf5268f7ff7478e0b1afa46a --- /dev/null +++ b/sum23/lecture_materials/15_Errors/lec_15_error_handling_notes.ipynb @@ -0,0 +1,1093 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Error handling" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# import statements\n", + "import math" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Warmup\n", + "\n", + "### Warmup 1: How does this recursion work? Try it in Python tutor" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def chop(s):\n", + " if len(s) < 3:\n", + " return s[0]\n", + " else:\n", + " return s[1] + chop(s[2:])\n", + "\n", + "chop(\"abcdefghijklmnop\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Now, by hand, figure out this output\n", + "chop(\"987654\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lecture 25: Error Handling\n", + "\n", + "**Learing Objectives:**\n", + " \n", + "- Explain the purpose of assert statements, try/except blocks, and raise statements.\n", + "\n", + "- Use an assert statement to force a program to crash, and trace code that uses assert.\n", + "\n", + "- Use try/except blocks to catch runtime errors and deal with them\n", + " - by specifying the exception(s) caught\n", + " - by using the exception object\n", + "\n", + "- Use the raise statement to raise an exception that may be caught in another part of the program\n", + "\n", + "- Hand trace code that uses assert, try/except blocks and raise statements\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Why might you want your code to crash more?\n", + "\n", + "- It is easier to debug the program if we get a stack trace\n", + "- Semantic errors are the scariest because we don't get any kind of error\n", + "\n", + "### When is it fine for your code to crash less?\n", + "\n", + "- When user enters incorrect input, we simply want to display an error message and not crash\n", + "- When the program has syntax error, we definitely want the program to crash\n", + "\n", + "<div>\n", + "<img src=\"attachment:Theme.png\" width=\"600\"/>\n", + "</div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pizza Analyzer" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def pizza_size(radius):\n", + " return (radius ** 2) * math.pi\n", + "\n", + "def slice_size(radius, slice_count):\n", + " total_size = pizza_size(radius)\n", + " return total_size * (1 / slice_count)\n", + "\n", + "def main():\n", + " for i in range(3):\n", + " # grab input\n", + " args = input(\"Enter pizza diameter(inches), slice count: \")\n", + " args = args.split(',')\n", + " radius = float(args[0].strip()) / 2\n", + " slices = int(args[1].strip())\n", + "\n", + " # pizza analysis\n", + " size = slice_size(radius, slices)\n", + " print('PIZZA: radius = {}, slices = {}, slice square inches = {}'\n", + " .format(radius, slices, size))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Try valid input of 4, 4 for main invocation" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter pizza diameter(inches), slice count: 4,4\n", + "PIZZA: radius = 2.0, slices = 4, slice square inches = 3.141592653589793\n", + "Enter pizza diameter(inches), slice count: 10,0\n" + ] + }, + { + "ename": "ZeroDivisionError", + "evalue": "division by zero", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[3], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mmain\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[2], line 17\u001b[0m, in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m 14\u001b[0m slices \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mint\u001b[39m(args[\u001b[38;5;241m1\u001b[39m]\u001b[38;5;241m.\u001b[39mstrip())\n\u001b[1;32m 16\u001b[0m \u001b[38;5;66;03m# pizza analysis\u001b[39;00m\n\u001b[0;32m---> 17\u001b[0m size \u001b[38;5;241m=\u001b[39m \u001b[43mslice_size\u001b[49m\u001b[43m(\u001b[49m\u001b[43mradius\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mslices\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 18\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mPIZZA: radius = \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m, slices = \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m, slice square inches = \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 19\u001b[0m \u001b[38;5;241m.\u001b[39mformat(radius, slices, size))\n", + "Cell \u001b[0;32mIn[2], line 6\u001b[0m, in \u001b[0;36mslice_size\u001b[0;34m(radius, slice_count)\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mslice_size\u001b[39m(radius, slice_count):\n\u001b[1;32m 5\u001b[0m total_size \u001b[38;5;241m=\u001b[39m pizza_size(radius)\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m total_size \u001b[38;5;241m*\u001b[39m (\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mslice_count\u001b[49m)\n", + "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero" + ] + } + ], + "source": [ + "main()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Can you think of any inputs that will make this program crash?\n", + "\n", + "Try each of these bad inputs:\n", + "- 10, 0: ZeroDivisionError\n", + "- 10: IndexError\n", + "- 10, hello: ValueError\n", + "- 10, 4.5: ValueError\n", + "- 10, -4: Semantic error\n", + "- -10, 4: Semantic error (scariest error for this example)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter pizza diameter(inches), slice count: 10, hi!\n" + ] + }, + { + "ename": "ValueError", + "evalue": "invalid literal for int() with base 10: 'hi!'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[4], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mmain\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[2], line 14\u001b[0m, in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m 12\u001b[0m args \u001b[38;5;241m=\u001b[39m args\u001b[38;5;241m.\u001b[39msplit(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m,\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 13\u001b[0m radius \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mfloat\u001b[39m(args[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39mstrip()) \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m2\u001b[39m\n\u001b[0;32m---> 14\u001b[0m slices \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstrip\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 16\u001b[0m \u001b[38;5;66;03m# pizza analysis\u001b[39;00m\n\u001b[1;32m 17\u001b[0m size \u001b[38;5;241m=\u001b[39m slice_size(radius, slices)\n", + "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'hi!'" + ] + } + ], + "source": [ + "main()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter pizza diameter(inches), slice count: -10, 4\n", + "PIZZA: radius = -5.0, slices = 4, slice square inches = 19.634954084936208\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "Interrupted by user", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[6], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mmain\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[2], line 11\u001b[0m, in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mmain\u001b[39m():\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m3\u001b[39m):\n\u001b[1;32m 10\u001b[0m \u001b[38;5;66;03m# grab input\u001b[39;00m\n\u001b[0;32m---> 11\u001b[0m args \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43minput\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mEnter pizza diameter(inches), slice count: \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 12\u001b[0m args \u001b[38;5;241m=\u001b[39m args\u001b[38;5;241m.\u001b[39msplit(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m,\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 13\u001b[0m radius \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mfloat\u001b[39m(args[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39mstrip()) \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m2\u001b[39m\n", + "File \u001b[0;32m~/miniforge3/lib/python3.10/site-packages/ipykernel/kernelbase.py:1191\u001b[0m, in \u001b[0;36mKernel.raw_input\u001b[0;34m(self, prompt)\u001b[0m\n\u001b[1;32m 1189\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mraw_input was called, but this frontend does not support input requests.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 1190\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m StdinNotImplementedError(msg)\n\u001b[0;32m-> 1191\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_input_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1192\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1193\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_parent_ident\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mshell\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1194\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_parent\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mshell\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1195\u001b[0m \u001b[43m \u001b[49m\u001b[43mpassword\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 1196\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/miniforge3/lib/python3.10/site-packages/ipykernel/kernelbase.py:1234\u001b[0m, in \u001b[0;36mKernel._input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m 1231\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m:\n\u001b[1;32m 1232\u001b[0m \u001b[38;5;66;03m# re-raise KeyboardInterrupt, to truncate traceback\u001b[39;00m\n\u001b[1;32m 1233\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInterrupted by user\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 1234\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m(msg) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1235\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m:\n\u001b[1;32m 1236\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mlog\u001b[38;5;241m.\u001b[39mwarning(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid Message:\u001b[39m\u001b[38;5;124m\"\u001b[39m, exc_info\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: Interrupted by user" + ] + } + ], + "source": [ + "main()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### What was the scariest error in the above examples?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# - -10, 4: Semantic error (scariest error for this example)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `assert` statements\n", + "- `assert` statements enable you to convert semantic errors into runtime errors\n", + " - runtime errors are easier to debug than semantic errors\n", + "- `assert` statements make your program very slow!\n", + " - so sometimes programmers disable these (we won't be learning about this)\n", + "- Syntax: `assert BOOLEAN_EXPRESSION`\n", + " - BOOLEAN_EXPRESSION evaluates to `True`: nothing happens (move on to next line of code)\n", + " - BOOLEAN_EXPRESSION evaluates to `False`: program carshes with `AssertionError`\n", + " \n", + "<div>\n", + "<img src=\"attachment:Assert.png\" width=\"450\"/>\n", + "</div>" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter your age: -5\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[8], line 4\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# simple example\u001b[39;00m\n\u001b[1;32m 3\u001b[0m age \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mint\u001b[39m(\u001b[38;5;28minput\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mEnter your age: \u001b[39m\u001b[38;5;124m\"\u001b[39m))\n\u001b[0;32m----> 4\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m age \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m \u001b[38;5;66;03m# if True, do nothing else, crash\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIn five years you will be\u001b[39m\u001b[38;5;124m\"\u001b[39m, age \u001b[38;5;241m+\u001b[39m \u001b[38;5;241m5\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myears old\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mAssertionError\u001b[0m: " + ] + } + ], + "source": [ + "# simple example\n", + "\n", + "age = int(input(\"Enter your age: \"))\n", + "assert age >= 0 # if True, do nothing else, crash\n", + "print(\"In five years you will be\", age + 5, \"years old\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "<div>\n", + "<img src=\"attachment:assert.png\" width=\"600\"/>\n", + "</div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Let's improvise error handling in pizza analyzer\n", + "- using `assert`:\n", + " - `assert` that radius is positive\n", + " - `assert` that slice count is positive" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "# Copy pasted code (not a typical thing which I will ask you to do) \n", + "# change function definitions to v2 and add the assert statements\n", + "\n", + "def pizza_size_v2(radius):\n", + " # TODO add assert statement here\n", + " assert radius >= 0\n", + " return (radius ** 2) * math.pi\n", + "\n", + "def slice_size_v2(radius, slice_count):\n", + " # TODO add assert statement here\n", + " assert slice_count >= 1\n", + " total_size = pizza_size_v2(radius)\n", + " return total_size * (1 / slice_count)\n", + "\n", + "def main_v2():\n", + " for i in range(3):\n", + " # grab input\n", + " args = input(\"Enter pizza diameter(inches), slice count: \")\n", + " args = args.split(',')\n", + " radius = float(args[0].strip()) / 2\n", + " slices = int(args[1].strip())\n", + "\n", + " # pizza analysis\n", + " size = slice_size_v2(radius, slices)\n", + " print('PIZZA: radius = {}, slices = {}, slice square inches = {}'\n", + " .format(radius, slices, size))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Try these problematic inputs for the main() function invocation\n", + "\n", + "- 10, -4: Semantic error\n", + "- -10, 4: Semantic error (scariest error for this example)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter pizza diameter(inches), slice count: -10, 4\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[15], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mmain_v2\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[14], line 24\u001b[0m, in \u001b[0;36mmain_v2\u001b[0;34m()\u001b[0m\n\u001b[1;32m 21\u001b[0m slices \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mint\u001b[39m(args[\u001b[38;5;241m1\u001b[39m]\u001b[38;5;241m.\u001b[39mstrip())\n\u001b[1;32m 23\u001b[0m \u001b[38;5;66;03m# pizza analysis\u001b[39;00m\n\u001b[0;32m---> 24\u001b[0m size \u001b[38;5;241m=\u001b[39m \u001b[43mslice_size_v2\u001b[49m\u001b[43m(\u001b[49m\u001b[43mradius\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mslices\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 25\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mPIZZA: radius = \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m, slices = \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m, slice square inches = \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 26\u001b[0m \u001b[38;5;241m.\u001b[39mformat(radius, slices, size))\n", + "Cell \u001b[0;32mIn[14], line 12\u001b[0m, in \u001b[0;36mslice_size_v2\u001b[0;34m(radius, slice_count)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mslice_size_v2\u001b[39m(radius, slice_count):\n\u001b[1;32m 10\u001b[0m \u001b[38;5;66;03m# TODO add assert statement here\u001b[39;00m\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m slice_count \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m---> 12\u001b[0m total_size \u001b[38;5;241m=\u001b[39m \u001b[43mpizza_size_v2\u001b[49m\u001b[43m(\u001b[49m\u001b[43mradius\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 13\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m total_size \u001b[38;5;241m*\u001b[39m (\u001b[38;5;241m1\u001b[39m \u001b[38;5;241m/\u001b[39m slice_count)\n", + "Cell \u001b[0;32mIn[14], line 6\u001b[0m, in \u001b[0;36mpizza_size_v2\u001b[0;34m(radius)\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpizza_size_v2\u001b[39m(radius):\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# TODO add assert statement here\u001b[39;00m\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m radius \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m (radius \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m \u001b[38;5;241m2\u001b[39m) \u001b[38;5;241m*\u001b[39m math\u001b[38;5;241m.\u001b[39mpi\n", + "\u001b[0;31mAssertionError\u001b[0m: " + ] + } + ], + "source": [ + "main_v2()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What if we want to keep running even if there is an error?\n", + "\n", + "That is, we don't want to pause the program execution for user's incorrect input" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## try / except blocks\n", + "\n", + "- `try` and `except` blocks come in pairs (runtime errors are “exceptions”)\n", + "- Python tries to run the code in the `try` block. \n", + " - If there is an exception, `try` block execution terminates and then `except` block gets executed(instead of crashing). This is called “catching” the exception.\n", + " - If there is no exception, `except` block doesn't get executed.\n", + "- Syntax (example):\n", + "```python\n", + "try:\n", + " flaky_function()\n", + "except:\n", + " print(\"error!\") # or some other handling\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### try / except examples\n", + "Try these examples using PythonTutor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 1: v1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " print(\"2 inverse is\", 1/2)\n", + " print(\"1 inverse is\", 1/1)\n", + " print(\"0 inverse is\", 1/0)\n", + " print(\"-1 inverse is\", -1/1)\n", + " print(\"-2 inverse is\", -1/1)\n", + "except:\n", + " print(\"that's all, folks!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 1: v2" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2 inverse is 0.5\n", + "1 inverse is 1.0\n", + "that's all, folks!\n", + "-1 inverse is -1.0\n", + "-2 inverse is -1.0\n" + ] + } + ], + "source": [ + "try:\n", + " print(\"2 inverse is\", 1/2)\n", + " print(\"1 inverse is\", 1/1)\n", + " print(\"0 inverse is\", 1/0)\n", + "except:\n", + " print(\"that's all, folks!\")\n", + "\n", + "try:\n", + " print(\"-1 inverse is\", -1/1)\n", + " print(\"-2 inverse is\", -1/1)\n", + "except:\n", + " print(\"This will never get executed!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 2: v1\n", + "- hierarchy of catching exceptions" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "f: let's call g\n", + "g: before buggy\n", + "buggy: about to fail\n", + "f: that didn't go so well\n" + ] + } + ], + "source": [ + "def buggy():\n", + " print(\"buggy: about to fail\")\n", + " print(\"buggy: infinity is \", 1/0)\n", + " print(\"buggy: oops!\") # never prints\n", + "\n", + "def g():\n", + " print(\"g: before buggy\")\n", + " buggy()\n", + " print(\"g: after buggy\") # never prints\n", + "\n", + "def f():\n", + " try:\n", + " print(\"f: let's call g\")\n", + " g()\n", + " print(\"f: g returned normally\") # never prints\n", + " except:\n", + " print(\"f: that didn't go so well\")\n", + "\n", + "f()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 2: v2\n", + "- hierarchy of catching exceptions" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "f: let's call g\n", + "g: before buggy\n", + "buggy: about to fail\n", + "g: that didn't go well\n", + "g: after buggy\n", + "f: g returned normally\n" + ] + } + ], + "source": [ + "def buggy():\n", + " print(\"buggy: about to fail\")\n", + " print(\"buggy: infinity is \", 1/0)\n", + " print(\"buggy: oops!\") # never prints\n", + "\n", + "def g():\n", + " print(\"g: before buggy\")\n", + " try:\n", + " buggy()\n", + " except:\n", + " print(\"g: that didn't go well\")\n", + " print(\"g: after buggy\") \n", + "\n", + "def f():\n", + " try:\n", + " print(\"f: let's call g\")\n", + " g()\n", + " print(\"f: g returned normally\") \n", + " except:\n", + " print(\"f: that didn't go so well\") # never prints\n", + "\n", + "f()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 2: v3\n", + "- hierarchy of catching exceptions" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "f: let's call g\n", + "g: before buggy\n", + "buggy: about to fail\n", + "buggy: oops!\n", + "g: after buggy\n", + "f: g returned normally\n" + ] + } + ], + "source": [ + "def buggy():\n", + " try:\n", + " print(\"buggy: about to fail\")\n", + " print(\"buggy: infinity is \", 1/0)\n", + " except:\n", + " print(\"buggy: oops!\") \n", + "\n", + "def g():\n", + " print(\"g: before buggy\")\n", + " try:\n", + " buggy()\n", + " except:\n", + " print(\"g: that didn't go well\") # never prints\n", + " print(\"g: after buggy\")\n", + "\n", + "def f():\n", + " try:\n", + " print(\"f: let's call g\")\n", + " g()\n", + " print(\"f: g returned normally\") \n", + " except:\n", + " print(\"f: that didn't go so well\") # never prints\n", + "\n", + "f()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### What if we want to know the reason for the exception?\n", + "\n", + "- Syntax (example):\n", + "```python\n", + "try:\n", + " flaky_function()\n", + "except Exception as e:\n", + " print(\"error because:\", str(e))\n", + " print(\"type of exception:\", type(e))\n", + "```\n", + "- `Exception` is a type.\n", + "- e an object instance of of type `Exception` (very general)\n", + " - there are different types of exceptions\n", + "- `str(e)` gives you the reason for the exception.\n", + "- `type(e)` will give you the type of the exception." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Let's improvise error handling in pizza analyzer more\n", + "- using `try` ... `except` ... " + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "def main_v3():\n", + " for i in range(3):\n", + " # grab input\n", + " args = input(\"Enter pizza diameter(inches), slice count: \")\n", + " args = args.split(',')\n", + "\n", + "\n", + " # pizza analysis TODO add try/except here\n", + " try:\n", + " radius = float(args[0].strip()) / 2\n", + " slices = int(args[1].strip())\n", + " size = slice_size_v2(radius, slices)\n", + " print('PIZZA: radius = {}, slices = {}, slice square inches = {}'\n", + " .format(radius, slices, size))\n", + " except Exception as e:\n", + " print(\"error because: \",str(e))\n", + " print(\"type of error: \", type(e))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Try these problematic inputs for the main() function invocation\n", + "\n", + "- 10, 0: ZeroDivisionError\n", + "- 10: IndexError\n", + "- 10, hello: ValueError\n", + "- 10, 4.5: ValueError\n", + "- 10, -4: AssertionError (after we wrote assert statement)\n", + "- -10, 4: AssertionError (after we wrote assert statement)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter pizza diameter(inches), slice count: 10,4.5\n", + "error because: invalid literal for int() with base 10: '4.5'\n", + "type of error: <class 'ValueError'>\n", + "Enter pizza diameter(inches), slice count: 10, -4\n", + "error because: \n", + "type of error: <class 'AssertionError'>\n", + "Enter pizza diameter(inches), slice count: 10, 0\n", + "error because: \n", + "type of error: <class 'AssertionError'>\n" + ] + } + ], + "source": [ + "main_v3()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `Exception` is too broad\n", + "- it catches many types of exceptions\n", + "- you do not want your except block to catch every possible exception!" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's create an intentional SyntaxError\n", + "\n", + "def main_v4():\n", + " for i in range(5):\n", + " try:\n", + " # grab input\n", + " args = input(\"Enter pizza diameter(inches), slice count: \")\n", + " args = argssssss.split(',')\n", + " radius = float(args[0].strip()) / 2\n", + " slices = int(args[1].strip())\n", + " except Exception as e:\n", + " print(\"Bad input & reason is:\", str(e))\n", + " print(\"Type of exception:\", type(e))\n", + " \n", + " try:\n", + " # pizza analysis\n", + " size = slice_size_v2(radius, slices)\n", + " print('PIZZA: radius = {}, slices = {}, slice square inches = {}'\n", + " .format(radius, slices, size))\n", + " except Exception as e:\n", + " print(\"Pizza analysis error & reason is:\", str(e))\n", + " print(\"Type of exception:\", type(e))" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter pizza diameter(inches), slice count: 10,4\n", + "Bad input & reason is: name 'argssssss' is not defined\n", + "Type of exception: <class 'NameError'>\n", + "Pizza analysis error & reason is: local variable 'radius' referenced before assignment\n", + "Type of exception: <class 'UnboundLocalError'>\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "Interrupted by user", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[27], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mmain_v4\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# oops, we made our program way too robus!\u001b[39;00m\n", + "Cell \u001b[0;32mIn[26], line 7\u001b[0m, in \u001b[0;36mmain_v4\u001b[0;34m()\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m5\u001b[39m):\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 6\u001b[0m \u001b[38;5;66;03m# grab input\u001b[39;00m\n\u001b[0;32m----> 7\u001b[0m args \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43minput\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mEnter pizza diameter(inches), slice count: \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 8\u001b[0m args \u001b[38;5;241m=\u001b[39m argssssss\u001b[38;5;241m.\u001b[39msplit(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m,\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 9\u001b[0m radius \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mfloat\u001b[39m(args[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39mstrip()) \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m2\u001b[39m\n", + "File \u001b[0;32m~/miniforge3/lib/python3.10/site-packages/ipykernel/kernelbase.py:1191\u001b[0m, in \u001b[0;36mKernel.raw_input\u001b[0;34m(self, prompt)\u001b[0m\n\u001b[1;32m 1189\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mraw_input was called, but this frontend does not support input requests.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 1190\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m StdinNotImplementedError(msg)\n\u001b[0;32m-> 1191\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_input_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1192\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1193\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_parent_ident\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mshell\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1194\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_parent\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mshell\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1195\u001b[0m \u001b[43m \u001b[49m\u001b[43mpassword\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 1196\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/miniforge3/lib/python3.10/site-packages/ipykernel/kernelbase.py:1234\u001b[0m, in \u001b[0;36mKernel._input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m 1231\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m:\n\u001b[1;32m 1232\u001b[0m \u001b[38;5;66;03m# re-raise KeyboardInterrupt, to truncate traceback\u001b[39;00m\n\u001b[1;32m 1233\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInterrupted by user\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 1234\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m(msg) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1235\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m:\n\u001b[1;32m 1236\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mlog\u001b[38;5;241m.\u001b[39mwarning(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid Message:\u001b[39m\u001b[38;5;124m\"\u001b[39m, exc_info\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: Interrupted by user" + ] + } + ], + "source": [ + "main_v4() # oops, we made our program way too robus!\n", + "\n", + "# In this case, it's a syntax error, so the program will never work\n", + "# We want the program to crash so that we know we have to fix it" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### How can we make `except` block catch specific exceptions?\n", + "\n", + "- Syntax (example):\n", + "```python\n", + "try:\n", + " flaky_function()\n", + "except (ValueError, IndexError) as e:\n", + " print(\"error because:\", str(e))\n", + " print(\"type of exception:\", type(e))\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's fix our except blocks\n", + "# Try introducing the intentional SyntaxError now\n", + "\n", + "def main_v5():\n", + " for i in range(5):\n", + " try:\n", + " # grab input\n", + " args = input(\"Enter pizza diameter(inches), slice count: \")\n", + " args = argssssssss.split(',')\n", + " radius = float(args[0].strip()) / 2\n", + " slices = int(args[1].strip())\n", + " except (ValueError, IndexError) as e:\n", + " print(\"Bad input & reason is:\", str(e))\n", + " print(\"Type of exception:\", type(e))\n", + " continue\n", + " \n", + " try:\n", + " # pizza analysis\n", + " size = slice_size_v2(radius, slices)\n", + " print('PIZZA: radius = {}, slices = {}, slice square inches = {}'\n", + " .format(radius, slices, size))\n", + " except Exception as e:\n", + " print(\"Pizza analysis error & reason is:\", str(e))\n", + " print(\"Type of exception:\", type(e))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Try these problematic inputs for the main() function invocation\n", + "\n", + "- 10, 0: ZeroDivisionError\n", + "- 10: IndexError\n", + "- 10, hello: ValueError\n", + "- 10, 4.5: ValueError\n", + "- 10, -4: AssertionError (after we wrote assert statement)\n", + "- -10, 4: AssertionError (after we wrote assert statement)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter pizza diameter(inches), slice count: 10,4.5\n" + ] + }, + { + "ename": "NameError", + "evalue": "name 'argssssssss' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[31], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mmain_v5\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[30], line 9\u001b[0m, in \u001b[0;36mmain_v5\u001b[0;34m()\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 7\u001b[0m \u001b[38;5;66;03m# grab input\u001b[39;00m\n\u001b[1;32m 8\u001b[0m args \u001b[38;5;241m=\u001b[39m \u001b[38;5;28minput\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mEnter pizza diameter(inches), slice count: \u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m----> 9\u001b[0m args \u001b[38;5;241m=\u001b[39m \u001b[43margssssssss\u001b[49m\u001b[38;5;241m.\u001b[39msplit(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m,\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 10\u001b[0m radius \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mfloat\u001b[39m(args[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39mstrip()) \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m2\u001b[39m\n\u001b[1;32m 11\u001b[0m slices \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mint\u001b[39m(args[\u001b[38;5;241m1\u001b[39m]\u001b[38;5;241m.\u001b[39mstrip())\n", + "\u001b[0;31mNameError\u001b[0m: name 'argssssssss' is not defined" + ] + } + ], + "source": [ + "main_v5()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exception hierarchy\n", + "- It helps to know some common excpeptions and to know their hierarchy.\n", + "- Don't try to memorize this but do make a note of the exceptions that occur the most often.\n", + "- Python documentation: https://docs.python.org/3/library/exceptions.html." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `raise` statements\n", + "- Rather than using assert we can also raise a specific error. \n", + "\n", + "- Syntax (example):\n", + "```python\n", + "if BOOLEAN_CONDITION:\n", + " raise ArithmeticError(\"details of error\")\n", + "```\n", + "\n", + "<div>\n", + "<img src=\"attachment:raise.png\" width=\"500\"/>\n", + "</div>" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "enter your age: -5\n" + ] + }, + { + "ename": "ArithmeticError", + "evalue": "age can't be negative", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mArithmeticError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[32], line 6\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m# previously: assert a >= 0\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m age \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mArithmeticError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mage can\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt be negative\u001b[39m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;66;03m# we can 'raise' a relevant exception\u001b[39;00m\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124min five years you will be\u001b[39m\u001b[38;5;124m\"\u001b[39m, age \u001b[38;5;241m+\u001b[39m \u001b[38;5;241m5\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myears old\u001b[39m\u001b[38;5;124m\"\u001b[39m) \n", + "\u001b[0;31mArithmeticError\u001b[0m: age can't be negative" + ] + } + ], + "source": [ + "# simple example: raise exceptions instead of using assert statements\n", + "\n", + "age = int(input(\"enter your age: \"))\n", + "# previously: assert a >= 0\n", + "if age < 0:\n", + " raise ArithmeticError(\"age can't be negative\") # we can 'raise' a relevant exception\n", + "print(\"in five years you will be\", age + 5, \"years old\") " + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def pizza_size_v2(radius):\n", + " assert radius >= 0\n", + " return (radius ** 2) * math.pi\n", + "\n", + "def slice_size_v2(radius, slice_count):\n", + " assert slice_count >= 0\n", + " total_size = pizza_size_v2(radius)\n", + " return total_size * (1 / slice_count)\n", + "\n", + "def main_v6():\n", + " for i in range(5):\n", + " # grab input\n", + " try:\n", + " args = input(\"Enter pizza diameter(inches), slice count: \")\n", + " args = args.split(',')\n", + " radius = float(args[0].strip()) / 2\n", + " slices = int(args[1].strip())\n", + " except (ValueError, TypeError, IndexError) as e:\n", + " print(\"Bad input & reason is:\", str(e))\n", + " print(\"Type of exception:\", type(e))\n", + " continue\n", + "\n", + " # pizza analysis\n", + " try:\n", + " size = slice_size_v2(radius, slices)\n", + " print('PIZZA: radius={}, slices={}, slice square inches={}'\n", + " .format(radius, slices, size))\n", + " except (ZeroDivisionError, AssertionError) as e:\n", + " print(\"Pizza analysis error!\", str(e))\n", + " print(\"Type of exception:\", type(e))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Try these problematic inputs for the main() function invocation\n", + "\n", + "- 10, -4: ArithmeticError (after we wrote assert statement)\n", + "- -10, 4: ArithmeticError (after we wrote assert statement)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter pizza diameter(inches), slice count: 20,0\n", + "Pizza analysis error! division by zero\n", + "Type of exception: <class 'ZeroDivisionError'>\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "Interrupted by user", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[34], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mmain_v6\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[33], line 14\u001b[0m, in \u001b[0;36mmain_v6\u001b[0;34m()\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m5\u001b[39m):\n\u001b[1;32m 12\u001b[0m \u001b[38;5;66;03m# grab input\u001b[39;00m\n\u001b[1;32m 13\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 14\u001b[0m args \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43minput\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mEnter pizza diameter(inches), slice count: \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 15\u001b[0m args \u001b[38;5;241m=\u001b[39m args\u001b[38;5;241m.\u001b[39msplit(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m,\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 16\u001b[0m radius \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mfloat\u001b[39m(args[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39mstrip()) \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m2\u001b[39m\n", + "File \u001b[0;32m~/miniforge3/lib/python3.10/site-packages/ipykernel/kernelbase.py:1191\u001b[0m, in \u001b[0;36mKernel.raw_input\u001b[0;34m(self, prompt)\u001b[0m\n\u001b[1;32m 1189\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mraw_input was called, but this frontend does not support input requests.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 1190\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m StdinNotImplementedError(msg)\n\u001b[0;32m-> 1191\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_input_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1192\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1193\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_parent_ident\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mshell\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1194\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_parent\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mshell\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1195\u001b[0m \u001b[43m \u001b[49m\u001b[43mpassword\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 1196\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/miniforge3/lib/python3.10/site-packages/ipykernel/kernelbase.py:1234\u001b[0m, in \u001b[0;36mKernel._input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m 1231\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m:\n\u001b[1;32m 1232\u001b[0m \u001b[38;5;66;03m# re-raise KeyboardInterrupt, to truncate traceback\u001b[39;00m\n\u001b[1;32m 1233\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInterrupted by user\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 1234\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m(msg) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1235\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m:\n\u001b[1;32m 1236\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mlog\u001b[38;5;241m.\u001b[39mwarning(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid Message:\u001b[39m\u001b[38;5;124m\"\u001b[39m, exc_info\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: Interrupted by user" + ] + } + ], + "source": [ + "main_v6()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}