Compare commits
10 Commits
d9456ce2cd
...
e7d57eefd8
Author | SHA1 | Date | |
---|---|---|---|
e7d57eefd8 | |||
603a0b8d4c | |||
dea7029598 | |||
987d203eba | |||
1058709c03 | |||
3a8136e22c | |||
ce4e78cabf | |||
53ee3577a1 | |||
4a0ac4a74b | |||
acefb913f4 |
@ -235,18 +235,21 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 5,
|
||||
"id": "5022b7c8-a19f-45cb-9d40-58abc48de961",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "SyntaxError",
|
||||
"evalue": "expected 'except' or 'finally' block (572013031.py, line 6)",
|
||||
"ename": "NameError",
|
||||
"evalue": "name 'd' is not defined",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;36m Cell \u001b[0;32mIn[10], line 6\u001b[0;36m\u001b[0m\n\u001b[0;31m print(\"hello\")\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m expected 'except' or 'finally' block\n"
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[5], line 5\u001b[0m\n\u001b[1;32m 3\u001b[0m b \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m#c = a / b\u001b[39;00m\n\u001b[0;32m----> 5\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43md\u001b[49m)\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlast line of try\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mZeroDivisionError\u001b[39;00m:\n",
|
||||
"\u001b[0;31mNameError\u001b[0m: name 'd' is not defined"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -254,11 +257,14 @@
|
||||
"try:\n",
|
||||
" a = 3\n",
|
||||
" b = 0\n",
|
||||
" c = a / b\n",
|
||||
" #c = a / b\n",
|
||||
" print(d)\n",
|
||||
" print(\"last line of try\")\n",
|
||||
"except ZeroDivisionError:\n",
|
||||
" c = 0\n",
|
||||
" print(f\"can't divide by zero, set c = {c}\")\n",
|
||||
"#except NameError:\n",
|
||||
"# print(\"used unknown name\")\n",
|
||||
"print(\"and then this happens\")"
|
||||
]
|
||||
},
|
||||
@ -274,7 +280,7 @@
|
||||
"```python\n",
|
||||
"# multiple except blocks for different behaviors\n",
|
||||
"try:\n",
|
||||
" something():\n",
|
||||
" something()\n",
|
||||
"except ValueError:\n",
|
||||
" ...\n",
|
||||
"except IndexError:\n",
|
||||
@ -284,7 +290,7 @@
|
||||
"```python\n",
|
||||
"# one block w/ multiple types in a tuple\n",
|
||||
"try:\n",
|
||||
" something()\n",
|
||||
" somthing()\n",
|
||||
"except (ValueError, IndexError, KeyError): # tuple of return values\n",
|
||||
" ...\n",
|
||||
"```\n",
|
||||
@ -293,9 +299,10 @@
|
||||
"# base exception type, use sparingly\n",
|
||||
"try:\n",
|
||||
" something()\n",
|
||||
"except ArithmeticError: # catches all errors derived from ArithmeticError\n",
|
||||
" ...\n",
|
||||
"except Exception: # catches all runtime exceptions\n",
|
||||
" ...\n",
|
||||
"except ArithmeticError: # catches all errors derived from ArithmeticError\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@ -328,7 +335,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"execution_count": 7,
|
||||
"id": "fd6d0e12-eae2-466e-8536-db5d246091f0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@ -341,7 +348,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 20,
|
||||
"id": "58c691a9-14ed-4fe1-9b0d-eb9b52a4d44d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@ -351,7 +358,7 @@
|
||||
"9"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"execution_count": 20,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -362,25 +369,42 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"execution_count": 27,
|
||||
"id": "5fd8e7ee-53c6-4cd1-8748-cd66f06da9ac",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "ValueError",
|
||||
"evalue": "f requires a positive argument",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[11], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mf\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n",
|
||||
"Cell \u001b[0;32mIn[9], line 3\u001b[0m, in \u001b[0;36mf\u001b[0;34m(positive)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mf\u001b[39m(positive):\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m positive \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mf requires a positive argument\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m positive \u001b[38;5;241m*\u001b[39m positive\n",
|
||||
"\u001b[0;31mValueError\u001b[0m: f requires a positive argument"
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"got an error: f requires a positive argument\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"f(-1)"
|
||||
"try:\n",
|
||||
" y = f(-1)\n",
|
||||
"except ValueError as exc:\n",
|
||||
" y = 0\n",
|
||||
" print(\"got an error: \", exc)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"id": "769fb253-ae47-4e47-a6fd-9a37e1ef3d5e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(y)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -404,6 +428,7 @@
|
||||
"source": [
|
||||
"class InvalidColor(Exception):\n",
|
||||
" \"\"\" This exception is raised when an invalid color is passed. \"\"\"\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"VALID_COLORS = (...)\n",
|
||||
"\n",
|
||||
@ -448,7 +473,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"execution_count": 30,
|
||||
"id": "320d3309-099a-4f2e-9096-983101bfc157",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@ -456,21 +481,22 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"got a value error error message\n",
|
||||
"else executed\n",
|
||||
"always prints at the end\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"try:\n",
|
||||
" #pass\n",
|
||||
" raise ValueError(\"error message\")\n",
|
||||
" 1 / 2\n",
|
||||
"except ValueError as e:\n",
|
||||
" print(\"got a value error\", e)\n",
|
||||
" print(\"got a value error:\", e)\n",
|
||||
"except Exception as e:\n",
|
||||
" print(\"got some other error:\", type(e), e)\n",
|
||||
"else:\n",
|
||||
" print(\"no exception raised\")\n",
|
||||
" print(\"else executed\")\n",
|
||||
"finally:\n",
|
||||
" print(\"always prints at the end\")"
|
||||
" print(\"always prints at the end\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -14,7 +14,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"execution_count": 1,
|
||||
"id": "feaa69a2",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -38,6 +38,7 @@
|
||||
" self.year = 1\n",
|
||||
" self.major = \"Undeclared\"\n",
|
||||
" self.course_grades = {}\n",
|
||||
" self.extracurriculars = []\n",
|
||||
" \n",
|
||||
" def add_grade(self, course_name, grade):\n",
|
||||
" self.course_grades[course_name] = grade\n",
|
||||
@ -55,7 +56,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 45,
|
||||
"id": "c410fb1d",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -70,7 +71,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"execution_count": 46,
|
||||
"id": "f9deab26",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -80,8 +81,8 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Student(name=Adam, id=1, gpa=0)\n",
|
||||
"Student(name=Beth, id=2, gpa=3.65)\n"
|
||||
"Student(name=Adam, id=8, gpa=0)\n",
|
||||
"Student(name=Beth, id=9, gpa=3.65)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -168,7 +169,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"execution_count": 49,
|
||||
"id": "47f7dfc9",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -187,7 +188,8 @@
|
||||
" \n",
|
||||
" # overrides parent's add_grade\n",
|
||||
" def add_grade(self, course_name, grade):\n",
|
||||
" print(\"Sorry, you cannot add grades to Alums\")\n",
|
||||
" raise NotImplementedError(\"cannot add grades to Alum\")\n",
|
||||
" #print(\"Sorry, you cannot add grades to Alums\")\n",
|
||||
" # we choose not call super().add_grade here\n",
|
||||
" \n",
|
||||
" # overrides parent's __repr__\n",
|
||||
@ -200,7 +202,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"execution_count": 51,
|
||||
"id": "4811b0fd",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -210,9 +212,8 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Student(name=Charlie, id=3, gpa=0) is an alum\n",
|
||||
"6 years since graduation\n",
|
||||
"Sorry, you cannot add grades to Alums\n"
|
||||
"Student(name=Charlie, id=13, gpa=0) is an alum\n",
|
||||
"6 years since graduation\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -221,7 +222,7 @@
|
||||
"0"
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"execution_count": 51,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -230,13 +231,13 @@
|
||||
"alum1 = Alum(\"Charlie\", 2016)\n",
|
||||
"print(alum1)\n",
|
||||
"print(alum1.years_since_graduation(2022), \"years since graduation\")\n",
|
||||
"alum1.add_grade(\"Python\", \"B\")\n",
|
||||
"#alum1.add_grade(\"Python\", \"B\")\n",
|
||||
"alum1.gpa"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"execution_count": 54,
|
||||
"id": "18a75666-9986-4e2b-9d55-ec0e0b9e930d",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -248,13 +249,27 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 56,
|
||||
"id": "b6719a36-b827-4373-87e0-23714438b83f",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "TypeError",
|
||||
"evalue": "unsupported operand type(s) for +: 'Alum' and 'Alum'",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[56], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43malum1\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43malum2\u001b[49m\n",
|
||||
"\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'Alum' and 'Alum'"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"alum1 + alum2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@ -278,7 +293,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"execution_count": 8,
|
||||
"id": "a46d5b02",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -290,7 +305,7 @@
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -301,12 +316,23 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 9,
|
||||
"id": "d3596a45-2c00-4541-910d-08251d3f9c5f",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# same as?\n",
|
||||
"type(7) == int"
|
||||
@ -314,7 +340,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 10,
|
||||
"id": "eaa8b6db-e7df-4137-b4c8-67dfa0be06d5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@ -324,7 +350,7 @@
|
||||
"False"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -335,7 +361,28 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"execution_count": 57,
|
||||
"id": "9cfc8480-ecca-4f80-9dfe-70a655bc5b3c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 57,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"isinstance(7, object)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 62,
|
||||
"id": "0e50f7bc-541e-4fec-9cd6-ad708f312831",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@ -345,32 +392,75 @@
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"execution_count": 62,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# isinstance checks the inheritance hierarchy \n",
|
||||
"isinstance(7, object)"
|
||||
"isinstance(alum2, object)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 64,
|
||||
"id": "34e491d5-ac5c-4dc9-b059-491e0f0f73b0",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"False"
|
||||
]
|
||||
},
|
||||
"execution_count": 64,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"type(alum2) == Student"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 65,
|
||||
"id": "cd55fd8d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 65,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"isinstance([1, 2, 3], list)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 17,
|
||||
"id": "feb9f2ac",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"s1 = Student(\"Sarah\")\n",
|
||||
"isinstance(s1, Student)"
|
||||
@ -378,10 +468,21 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 18,
|
||||
"id": "e6a2f3b1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# child classes are instances of parent types\n",
|
||||
"alum1 = Alum(\"Charlie\", 2016)\n",
|
||||
@ -390,10 +491,21 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 19,
|
||||
"id": "8f759efb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"False"
|
||||
]
|
||||
},
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# but not vice-versa\n",
|
||||
"isinstance(s1, Alum)"
|
||||
@ -401,7 +513,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"execution_count": 20,
|
||||
"id": "1d52b927",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -414,7 +526,7 @@
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[15], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# takes class names\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;43missubclass\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43malum1\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mStudent\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"Cell \u001b[0;32mIn[20], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# takes class names\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;43missubclass\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43malum1\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mStudent\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"\u001b[0;31mTypeError\u001b[0m: issubclass() arg 1 must be a class"
|
||||
]
|
||||
}
|
||||
@ -426,7 +538,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"execution_count": 22,
|
||||
"id": "a71ee1cb",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -435,16 +547,16 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"False"
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"issubclass(Student, Alum)"
|
||||
"issubclass(Alum, Student)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -478,7 +590,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"execution_count": 66,
|
||||
"id": "1d4e00ca",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -488,7 +600,7 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Help on Alum in module __main__ object:\n",
|
||||
"Help on class Alum in module __main__:\n",
|
||||
"\n",
|
||||
"class Alum(Student)\n",
|
||||
" | Alum(name, grad_year)\n",
|
||||
@ -529,13 +641,100 @@
|
||||
" | ----------------------------------------------------------------------\n",
|
||||
" | Data and other attributes inherited from Student:\n",
|
||||
" | \n",
|
||||
" | next_id_counter = 5\n",
|
||||
" | next_id_counter = 16\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"help(alum1)"
|
||||
"help(Alum)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 67,
|
||||
"id": "45f732f0-2036-416e-a44c-70b99b18a960",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(__main__.Alum, __main__.Student, object)"
|
||||
]
|
||||
},
|
||||
"execution_count": 67,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"Alum.__mro__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"id": "592f6930-cf36-4ec1-a4f3-ea1947fa7173",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Help on class super in module builtins:\n",
|
||||
"\n",
|
||||
"class super(object)\n",
|
||||
" | super() -> same as super(__class__, <first argument>)\n",
|
||||
" | super(type) -> unbound super object\n",
|
||||
" | super(type, obj) -> bound super object; requires isinstance(obj, type)\n",
|
||||
" | super(type, type2) -> bound super object; requires issubclass(type2, type)\n",
|
||||
" | Typical use to call a cooperative superclass method:\n",
|
||||
" | class C(B):\n",
|
||||
" | def meth(self, arg):\n",
|
||||
" | super().meth(arg)\n",
|
||||
" | This works for class methods too:\n",
|
||||
" | class C(B):\n",
|
||||
" | @classmethod\n",
|
||||
" | def cmeth(cls, arg):\n",
|
||||
" | super().cmeth(arg)\n",
|
||||
" | \n",
|
||||
" | Methods defined here:\n",
|
||||
" | \n",
|
||||
" | __get__(self, instance, owner=None, /)\n",
|
||||
" | Return an attribute of instance, which is of type owner.\n",
|
||||
" | \n",
|
||||
" | __getattribute__(self, name, /)\n",
|
||||
" | Return getattr(self, name).\n",
|
||||
" | \n",
|
||||
" | __init__(self, /, *args, **kwargs)\n",
|
||||
" | Initialize self. See help(type(self)) for accurate signature.\n",
|
||||
" | \n",
|
||||
" | __repr__(self, /)\n",
|
||||
" | Return repr(self).\n",
|
||||
" | \n",
|
||||
" | ----------------------------------------------------------------------\n",
|
||||
" | Static methods defined here:\n",
|
||||
" | \n",
|
||||
" | __new__(*args, **kwargs) from builtins.type\n",
|
||||
" | Create and return a new object. See help(type) for accurate signature.\n",
|
||||
" | \n",
|
||||
" | ----------------------------------------------------------------------\n",
|
||||
" | Data descriptors defined here:\n",
|
||||
" | \n",
|
||||
" | __self__\n",
|
||||
" | the instance invoking super(); may be None\n",
|
||||
" | \n",
|
||||
" | __self_class__\n",
|
||||
" | the type of the instance invoking super(); may be None\n",
|
||||
" | \n",
|
||||
" | __thisclass__\n",
|
||||
" | the class invoking super()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"help(super)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -584,12 +783,18 @@
|
||||
" def __init__(self,x,y):\n",
|
||||
" self.x = x\n",
|
||||
" self.y = y \n",
|
||||
"\n",
|
||||
" def dot_product(self, other):\n",
|
||||
" ...\n",
|
||||
" \n",
|
||||
"class Vec3:\n",
|
||||
" def __init__(self,x,y,z):\n",
|
||||
" self.x = x\n",
|
||||
" self.y = y \n",
|
||||
" self.z = z "
|
||||
" self.z = z \n",
|
||||
"\n",
|
||||
" def dot(self, other):\n",
|
||||
" ..."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -606,7 +811,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 43,
|
||||
"execution_count": 72,
|
||||
"id": "a2cddb6d",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -615,7 +820,10 @@
|
||||
"source": [
|
||||
"from abc import ABC, abstractmethod\n",
|
||||
"\n",
|
||||
"class Vector(ABC): \n",
|
||||
"class Vector(ABC): \n",
|
||||
" def print_x(self):\n",
|
||||
" print(self.x)\n",
|
||||
" \n",
|
||||
" @abstractmethod\n",
|
||||
" def dot_product(self, other):\n",
|
||||
" pass"
|
||||
@ -623,7 +831,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 44,
|
||||
"execution_count": 71,
|
||||
"id": "a32d26a8",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -631,13 +839,13 @@
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "TypeError",
|
||||
"evalue": "Can't instantiate abstract class Vector with abstract method dot_product",
|
||||
"evalue": "Can't instantiate abstract class Vector with abstract methods __repr__, dot_product",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[44], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# we can't instantiate abstract classes\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m v \u001b[38;5;241m=\u001b[39m \u001b[43mVector\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"\u001b[0;31mTypeError\u001b[0m: Can't instantiate abstract class Vector with abstract method dot_product"
|
||||
"Cell \u001b[0;32mIn[71], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# we can't instantiate abstract classes\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m v \u001b[38;5;241m=\u001b[39m \u001b[43mVector\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"\u001b[0;31mTypeError\u001b[0m: Can't instantiate abstract class Vector with abstract methods __repr__, dot_product"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -648,7 +856,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 45,
|
||||
"execution_count": 75,
|
||||
"id": "5a9ae047",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -675,7 +883,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 46,
|
||||
"execution_count": 76,
|
||||
"id": "e25536d1",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -710,6 +918,24 @@
|
||||
"print(isinstance(v3a, Vector))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 78,
|
||||
"id": "69ac4241-b251-4485-9ba9-3b0348d82c34",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"1\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"v2a.print_x()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 47,
|
||||
@ -762,7 +988,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 53,
|
||||
"execution_count": 79,
|
||||
"id": "4f98cf62-52da-4072-bf5a-da7de3ad9a98",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -793,7 +1019,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 54,
|
||||
"execution_count": 43,
|
||||
"id": "8faf9c31-33e4-42f1-a8e8-8b72a7f1f96f",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -803,7 +1029,29 @@
|
||||
"wrench = InventoryItem(\"Wrench\", 12.95, 10)\n",
|
||||
"hammer = InventoryItem(\"Hammer\", 16, 8)\n",
|
||||
"nails = InventoryItem(\"Nails\", 0.03, 1000)\n",
|
||||
"saw = InventoryItem(\"Saw\", 99)"
|
||||
"saw = InventoryItem(\"Saw\", 99)\n",
|
||||
"saw2 = InventoryItem(\"Saw\", 99)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 44,
|
||||
"id": "94f14911-335c-4097-8658-b9a30a70d53b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 44,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"saw == saw2"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -884,7 +1132,9 @@
|
||||
"id": "73195ac4-c0cc-4f8b-8852-2b63168e1713",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
"source": [
|
||||
"functools."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
886
13.python-data-model.ipynb
Normal file
886
13.python-data-model.ipynb
Normal file
@ -0,0 +1,886 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Python Data Model\n",
|
||||
"\n",
|
||||
"## Python Data Model\n",
|
||||
"\n",
|
||||
"Reference: https://docs.python.org/3/reference/datamodel.html\n",
|
||||
"\n",
|
||||
"### StaticArray Example\n",
|
||||
"\n",
|
||||
"To demonstrate operator overloading, we'll implement a sequence type seen in other languages known as a *static array*:\n",
|
||||
"\n",
|
||||
"- A static array is a sequence type (review: what makes a sequence type) where there is a fixed capacity to number of items the collection can hold.\n",
|
||||
"\n",
|
||||
"- Resizing of the array is not allowed after initialization. \n",
|
||||
"\n",
|
||||
"- We will define a class ``StaticArray`` that will allow use to use built-in python operators.\n",
|
||||
"\n",
|
||||
"We'll be able to use it like this:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
">>> from static_array import StaticArray\n",
|
||||
">>> sa = StaticArray([1, 2, 3])\n",
|
||||
">>> print(sa * 2)\n",
|
||||
"# should produce the following output:\n",
|
||||
"# [1, 2, 3, 1, 2, 3]\n",
|
||||
">>> print(sa[1])\n",
|
||||
"2\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from collections.abc import Iterable\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class StaticArray:\n",
|
||||
" def __init__(self, init_val, capacity=5):\n",
|
||||
" if isinstance(init_val, Iterable):\n",
|
||||
" self.items = list(init_val)\n",
|
||||
" self.capacity = len(self.items)\n",
|
||||
" else:\n",
|
||||
" self.items = [init_val] * capacity\n",
|
||||
" self.capacity = capacity\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sa = StaticArray([1, 2, 3])\n",
|
||||
"print(sa)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sa = StaticArray(0, 5)\n",
|
||||
"print(sa)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# we can fix that by defining a __repr__ method\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class StaticArray:\n",
|
||||
" def __init__(self, init_val, capacity=5):\n",
|
||||
" if isinstance(init_val, Iterable):\n",
|
||||
" self.items = list(init_val)\n",
|
||||
" self.capacity = len(self.items)\n",
|
||||
" else:\n",
|
||||
" self.items = [init_val] * capacity\n",
|
||||
" self.capacity = capacity\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return f\"StaticArray({self.items})\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"sa = StaticArray([1, 2, 3])\n",
|
||||
"print(sa)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sa = StaticArray(0, 5)\n",
|
||||
"print(sa)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Emulating Collections & Sequences\n",
|
||||
"\n",
|
||||
"**Collections**\n",
|
||||
"\n",
|
||||
"- Have a length: `len(obj)`\n",
|
||||
"- Can be iterated over: `for item in obj`\n",
|
||||
"- Can query for membership: `item in obj`\n",
|
||||
"\n",
|
||||
"**Sequences**\n",
|
||||
"\n",
|
||||
"- Everything a collection can do\n",
|
||||
"- Can be indexed: `obj[0]`\n",
|
||||
"\n",
|
||||
"| You Write... | Python Calls... |\n",
|
||||
"|--------------|-----------------|\n",
|
||||
"| `len(obj)` | `obj.__len__()` |\n",
|
||||
"| `for item in obj` | `obj.__iter__()` |\n",
|
||||
"| `item in obj` | `obj.__contains__(item)` |\n",
|
||||
"| `obj[i]` | `obj.__getitem__(i)` |\n",
|
||||
"| `obj[i] = x` | `obj.__setitem__(i, x)` |\n",
|
||||
"| `del obj[i]` | `obj.__delitem__(i)` |\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class StaticArray:\n",
|
||||
" def __init__(self, init_val, capacity=5):\n",
|
||||
" if isinstance(init_val, Iterable):\n",
|
||||
" self.items = list(init_val)\n",
|
||||
" self.capacity = len(self.items)\n",
|
||||
" else:\n",
|
||||
" self.items = [init_val] * capacity\n",
|
||||
" self.capacity = capacity\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return f\"StaticArray({self.items})\"\n",
|
||||
"\n",
|
||||
" def __str__(self):\n",
|
||||
" return f\"StaticArray({self.items})\"\n",
|
||||
"\n",
|
||||
" def __len__(self):\n",
|
||||
" return self.capacity\n",
|
||||
"\n",
|
||||
" def __contains__(self, item):\n",
|
||||
" return item in self.items\n",
|
||||
"\n",
|
||||
" def __getitem__(self, index):\n",
|
||||
" if index >= self.capacity or index < -self.capacity:\n",
|
||||
" raise IndexError(\"Index out of range\")\n",
|
||||
" return self.items[index]\n",
|
||||
"\n",
|
||||
" def __setitem__(self, index, val):\n",
|
||||
" if index >= self.capacity or index < -self.capacity:\n",
|
||||
" raise IndexError(\"Index out of range\")\n",
|
||||
" self.items[index] = val\n",
|
||||
"\n",
|
||||
" def __delitem__(self, index):\n",
|
||||
" raise NotImplementedError(\"StaticArray does not support deletion\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sa = StaticArray([1, \"hi\", 3.14, True])\n",
|
||||
"len(sa)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"42 in sa\n",
|
||||
"\"hi\" in sa"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sa[3]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sa[42] = \"hello\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Numeric Operators\n",
|
||||
"\n",
|
||||
"| You Write... | Python Calls... |\n",
|
||||
"|--------------|-----------------|\n",
|
||||
"| `x + y` | `x.__add__(y)` |\n",
|
||||
"| `x - y` | `x.__sub__(y)` |\n",
|
||||
"| `x * y` | `x.__mul__(y)` |\n",
|
||||
"| `x / y` | `x.__truediv__(y)` |\n",
|
||||
"| `x // y` | `x.__floordiv__(y)` |\n",
|
||||
"| `x % y` | `x.__mod__(y)` |\n",
|
||||
"| `x ** y` | `x.__pow__(y)` |\n",
|
||||
"| `x @ y` | `x.__matmul__(y)` |\n",
|
||||
"\n",
|
||||
"### Reverse / Reflected / Right Operators\n",
|
||||
"\n",
|
||||
"| You Write... | Python Calls... |\n",
|
||||
"|--------------|-----------------|\n",
|
||||
"| `x + y` | `y.__radd__(x)` |\n",
|
||||
"| `x - y` | `y.__rsub__(x)` |\n",
|
||||
"| `x * y` | `y.__rmul__(x)` |\n",
|
||||
"| `x / y` | `y.__rtruediv__(x)` |\n",
|
||||
"| `x // y` | `y.__rfloordiv__(x)` |\n",
|
||||
"| `x % y` | `y.__rmod__(x)` |\n",
|
||||
"| `x ** y` | `y.__rpow__(x)` |\n",
|
||||
"| `x @ y` | `y.__rmatmul__(x)` |\n",
|
||||
"\n",
|
||||
"![](images/reverse_operators.png)\n",
|
||||
"\n",
|
||||
"### Comparison Operators\n",
|
||||
"\n",
|
||||
"| You Write... | Python Calls... |\n",
|
||||
"|--------------|-----------------| \n",
|
||||
"| `x < y` | `x.__lt__(y)` |\n",
|
||||
"| `x <= y` | `x.__le__(y)` |\n",
|
||||
"| `x > y` | `x.__gt__(y)` |\n",
|
||||
"| `x >= y` | `x.__ge__(y)` |\n",
|
||||
"| `x == y` | `x.__eq__(y)` |\n",
|
||||
"| `x != y` | `x.__ne__(y)` |\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Iteration\n",
|
||||
"\n",
|
||||
"Iterable vs. Iterator (Review)\n",
|
||||
"\n",
|
||||
"Objects like lists, tuples, and strings are *iterable*.\n",
|
||||
"\n",
|
||||
"To keep track of the position within a given iteration (for loop, calls to `next`), Python uses an *iterator*."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ll = [1, 2, 3, 4]\n",
|
||||
"iterator = iter(ll)\n",
|
||||
"print(\"iterator 1 next()\", next(iterator))\n",
|
||||
"print(\"iterator 1 next()\", next(iterator))\n",
|
||||
"iterator2 = iter(ll)\n",
|
||||
"print(\"iterator 2 next()\", next(iterator2))\n",
|
||||
"print(\"iterator 1 next()\", next(iterator))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To be iterable, a class needs an `__iter__` method that returns an iterator.\n",
|
||||
"\n",
|
||||
"An iterator is an object with a `__next__` method that returns the next item in the iteration. It should raise `StopIteration` when there are no more items.\n",
|
||||
"\n",
|
||||
"Common Pattern: If a class only needs to be iterable once, it can return itself as the iterator, thus fulfilling both roles."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for i in iterable:\n",
|
||||
" print(i)\n",
|
||||
"\n",
|
||||
"iterator = iter(iterable)\n",
|
||||
"while True:\n",
|
||||
" print(next(iterator))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class SimpleRange:\n",
|
||||
" def __init__(self, n):\n",
|
||||
" self.current = 0\n",
|
||||
" self.n = n\n",
|
||||
"\n",
|
||||
" def __iter__(self):\n",
|
||||
" print(\"iter has been called\")\n",
|
||||
" return self\n",
|
||||
"\n",
|
||||
" def __next__(self):\n",
|
||||
" if self.current >= self.n:\n",
|
||||
" print(\"at the end\")\n",
|
||||
" raise StopIteration\n",
|
||||
" else:\n",
|
||||
" print(f\"next was called, moving {self.current} to {self.current+1}\")\n",
|
||||
" self.current += 1\n",
|
||||
" return self.current - 1\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return f\"SimpleRange({self.n}, current={self.current})\"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"iter has been called\n",
|
||||
"next was called, moving 0 to 1\n",
|
||||
"iter has been called\n",
|
||||
"next was called, moving 1 to 2\n",
|
||||
"0 1\n",
|
||||
"next was called, moving 2 to 3\n",
|
||||
"0 2\n",
|
||||
"at the end\n",
|
||||
"at the end\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"sr = SimpleRange(3)\n",
|
||||
"for i in sr:\n",
|
||||
" for j in sr:\n",
|
||||
" print(i, j)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sr = SimpleRange(5)\n",
|
||||
"siter = iter(sr)\n",
|
||||
"print(siter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"siter is sr"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"next(siter)\n",
|
||||
"print(siter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Iteration Advice \n",
|
||||
"\n",
|
||||
"1. Do not implement the ``__next__()`` in a class that should only be an iterable. \n",
|
||||
"2. In order to support multiple traversals, the iterator must be a seperate object. \n",
|
||||
"3. A common design pattern is to delegate iteration to a seperate class that is iterable.\n",
|
||||
"\n",
|
||||
"For example, defining an ``StaticArrayIterator`` class that is in charge iterating through the objects within an ``StaticArray`` object. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Adding __iter__ to StaticArray\n",
|
||||
"class StaticArrayIterator:\n",
|
||||
" def __init__(self, values):\n",
|
||||
" self.values = values\n",
|
||||
" self.position = 0\n",
|
||||
"\n",
|
||||
" def __next__(self):\n",
|
||||
" if self.position >= len(self.values):\n",
|
||||
" raise StopIteration\n",
|
||||
" item = self.values[self.position]\n",
|
||||
" self.position += 1\n",
|
||||
" return item\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return f\"iterating over {self.values}, at position {self.position}\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Adding __iter__\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class StaticArray:\n",
|
||||
" def __init__(self, capacity, initial=None):\n",
|
||||
" self._items = [initial] * capacity\n",
|
||||
" self._capacity = capacity\n",
|
||||
" self._iter_position = 0\n",
|
||||
"\n",
|
||||
" @classmethod\n",
|
||||
" def from_iterable(self, iterable):\n",
|
||||
" new_array = StaticArray(len(iterable))\n",
|
||||
" for idx, item in enumerate(iterable):\n",
|
||||
" new_array._items[idx] = item\n",
|
||||
" return new_array\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" # __repr__ is the unambiguous string representation\n",
|
||||
" # of an object\n",
|
||||
" return f\"StaticArray({self._capacity}, {self._items})\"\n",
|
||||
"\n",
|
||||
" def __str__(self):\n",
|
||||
" return repr(self._items)\n",
|
||||
"\n",
|
||||
" # Sequence Operations ####\n",
|
||||
"\n",
|
||||
" def __len__(self):\n",
|
||||
" return self._capacity\n",
|
||||
"\n",
|
||||
" def __contains__(self, x):\n",
|
||||
" return x in self._items\n",
|
||||
"\n",
|
||||
" def __getitem__(self, i):\n",
|
||||
" if i >= self._capacity or i < -self._capacity:\n",
|
||||
" raise IndexError # an invalid index\n",
|
||||
" return self._items[i]\n",
|
||||
"\n",
|
||||
" def __setitem__(self, i, x):\n",
|
||||
" if i >= self._capacity or i < -self._capacity:\n",
|
||||
" raise IndexError # an invalid index\n",
|
||||
" self._items[i] = x\n",
|
||||
"\n",
|
||||
" def __delitem__(self, i):\n",
|
||||
" raise NotImplementedError(\"Cannot delete from a static array\")\n",
|
||||
"\n",
|
||||
" # Iterable Operations ####\n",
|
||||
" def __iter__(self):\n",
|
||||
" return StaticArrayIterator(self._items.copy())\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 31,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[1, 2, 3, 4, 5]\n",
|
||||
"1 1\n",
|
||||
"1 2\n",
|
||||
"1 3\n",
|
||||
"1 4\n",
|
||||
"1 5\n",
|
||||
"2 1\n",
|
||||
"2 2\n",
|
||||
"2 3\n",
|
||||
"2 4\n",
|
||||
"2 5\n",
|
||||
"3 1\n",
|
||||
"3 2\n",
|
||||
"3 3\n",
|
||||
"3 4\n",
|
||||
"3 5\n",
|
||||
"4 1\n",
|
||||
"4 2\n",
|
||||
"4 3\n",
|
||||
"4 4\n",
|
||||
"4 5\n",
|
||||
"5 1\n",
|
||||
"5 2\n",
|
||||
"5 3\n",
|
||||
"5 4\n",
|
||||
"5 5\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"sa = StaticArray(5, 2)\n",
|
||||
"sa[0] = 1\n",
|
||||
"sa[1] = 2\n",
|
||||
"sa[2] = 3\n",
|
||||
"sa[3] = 4\n",
|
||||
"sa[4] = 5\n",
|
||||
"print(sa)\n",
|
||||
"for x in sa:\n",
|
||||
" for y in sa:\n",
|
||||
" print(x, y)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"## Context Managers / `with`\n",
|
||||
"\n",
|
||||
"We also saw this idea of needing to clean up after ourselves when we used `with` to open files.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"\n",
|
||||
"with open(filename) as f:\n",
|
||||
" # do things with f\n",
|
||||
" g(f)\n",
|
||||
"# f is guaranteed to be closed even if \n",
|
||||
"# exceptions are raised within with block\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### Yet another set of dunder methods..."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class DatabaseConnection:\n",
|
||||
" def __init__(self, username, password):\n",
|
||||
" # connect to database\n",
|
||||
" self.username = username\n",
|
||||
" self.password = password\n",
|
||||
" self.connected = True\n",
|
||||
"\n",
|
||||
" def __enter__(self):\n",
|
||||
" print(\"__enter__\")\n",
|
||||
" # must return self!\n",
|
||||
" return self\n",
|
||||
"\n",
|
||||
" def __exit__(self, exc_type, exc_val, exc_traceback):\n",
|
||||
" print(\"__exit__\")\n",
|
||||
" if exc_type:\n",
|
||||
" print(\"rolling back changes\")\n",
|
||||
" self.connected = False\n",
|
||||
"\n",
|
||||
" def query(self, sql):\n",
|
||||
" print(\"ran query\", sql)\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return f\"Connection connected={self.connected}\"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"db = DatabaseConnection(\"hello\", \"world\")\n",
|
||||
"db.query(\"SELECT * FROM users;\")\n",
|
||||
"# do something dangerous\n",
|
||||
"1 / 0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# our connection is possibly left in a broken state\n",
|
||||
"print(db)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with DatabaseConnection(\"hello\", \"world\") as db:\n",
|
||||
" # __enter__\n",
|
||||
" db.query(\"SELECT * from users;\")\n",
|
||||
" 1 / 0\n",
|
||||
" # __exit__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# changes were rolled back, and our connection is safe\n",
|
||||
"db.connected\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Callable Objects Examples\n",
|
||||
"\n",
|
||||
"Functions have a few attributes like `__name__` and `__doc__` that we can use to introspect on them."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 32,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"add\n",
|
||||
"Adds two numbers\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def add(x, y):\n",
|
||||
" \"\"\"Adds two numbers\"\"\"\n",
|
||||
" return x + y\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(add.__name__)\n",
|
||||
"print(add.__doc__)\n",
|
||||
"\n",
|
||||
"x = add"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"x.__name__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 48,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Example:\n",
|
||||
" def __init__(self, name):\n",
|
||||
" self.name = name\n",
|
||||
" self.num_calls = 0\n",
|
||||
" def __call__(self, **kwargs):\n",
|
||||
" print(self.num_calls)\n",
|
||||
" self.num_calls += 1\n",
|
||||
" print(self.name, \"got\", args)\n",
|
||||
"\n",
|
||||
"example = Example(\"one\")\n",
|
||||
"two = Example(\"two\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 47,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"7\n",
|
||||
"one got (1, 2, 3)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"example(1, 2, 3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 51,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2\n",
|
||||
"two got ()\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"two()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"They also have a `__call__` method that allows us to make our own objects callable. For example:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 54,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Memoized:\n",
|
||||
" def __init__(self, func):\n",
|
||||
" self.cache = {}\n",
|
||||
" self.wrapped_func = func\n",
|
||||
"\n",
|
||||
" def __call__(self, *args):\n",
|
||||
" if args not in self.cache:\n",
|
||||
" self.cache[args] = self.wrapped_func(*args)\n",
|
||||
" return self.cache[args]\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 55,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"running expensive_func\n",
|
||||
"6\n",
|
||||
"6\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"@Memoized\n",
|
||||
"def expensive_func(a, b, c):\n",
|
||||
" print(\"running expensive_func\")\n",
|
||||
" return a + b + c\n",
|
||||
"\n",
|
||||
"#expensive_func = Memoized(expensive_func)\n",
|
||||
"\n",
|
||||
"print(expensive_func(1, 2, 3))\n",
|
||||
"print(expensive_func(1, 2, 3))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class PartialFunc:\n",
|
||||
" # simplified functools.partial\n",
|
||||
"\n",
|
||||
" def __init__(self, func, *args, **kwargs):\n",
|
||||
" self.func = func\n",
|
||||
" self.args = args\n",
|
||||
" self.kwargs = kwargs\n",
|
||||
"\n",
|
||||
" def __call__(self, *args, **kwargs):\n",
|
||||
" temp_kwargs = self.kwargs.copy()\n",
|
||||
" temp_kwargs.update(kwargs)\n",
|
||||
" return self.func(*(self.args + args), **temp_kwargs)\n",
|
||||
"\n",
|
||||
" @property\n",
|
||||
" def __name__(self):\n",
|
||||
" return f\"{self.func.__name__}(args={self.args} kwargs={self.kwargs})\"\n",
|
||||
"\n",
|
||||
" @property\n",
|
||||
" def __doc__(self):\n",
|
||||
" return self.func.__doc__\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def add(x, y):\n",
|
||||
" \"\"\"Adds two numbers\"\"\"\n",
|
||||
" return x + y\n",
|
||||
"\n",
|
||||
"add_5 = PartialFunc(add, 5)\n",
|
||||
"print(add_5(10))\n",
|
||||
"\n",
|
||||
"print(add_5.__name__)\n",
|
||||
"print(add_5.__doc__)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"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.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
1301
14.more-classes.ipynb
Normal file
1301
14.more-classes.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
636
15.linked-lists-and-arrays.ipynb
Normal file
636
15.linked-lists-and-arrays.ipynb
Normal file
@ -0,0 +1,636 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4d5e8ae9-592e-48b1-bf17-9923d267349c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Data Structures: Linked Lists vs. Arrays\n",
|
||||
"\n",
|
||||
"This week we're going to look at implementations of core data structures in Python.\n",
|
||||
"\n",
|
||||
"We'll start with two different ways to represent sequential data: **linked lists** & **arrays**.\n",
|
||||
"\n",
|
||||
"Python's `list` could have chosen either of these, and in some languages like Java or C++ users explicitly choose the implementation most suited to their needs.\n",
|
||||
"\n",
|
||||
"## Arrays\n",
|
||||
"\n",
|
||||
"Arrays are blocks of contiguous memory. \n",
|
||||
"\n",
|
||||
"Each block is the same size, so you can find the memory location of a given block\n",
|
||||
"via `start_position + (idx * block_size)`. That will give the address of a given block, allowing **O(1)** access to any element.\n",
|
||||
"\n",
|
||||
"This means looking up the 0th element takes the same amount of time as the 1,000,00th. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e774f52f-63cc-4dcf-a8ec-e7ed9197f76f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Array:\n",
|
||||
" \"\"\"\n",
|
||||
" psuedocode class demonstrating array lookup \n",
|
||||
" \"\"\"\n",
|
||||
" def __init__(self, size, block_size=8):\n",
|
||||
" # need a contiguous block of free memory\n",
|
||||
" self.initial_memory_address = request_memory(amount=size*block_size)\n",
|
||||
" # each \"cell\" in the array needs to be the same number of bytes\n",
|
||||
" self.block_size = block_size\n",
|
||||
" # we need to know how many cells we need\n",
|
||||
" self.size = size\n",
|
||||
" \n",
|
||||
" def __getitem__(self, index):\n",
|
||||
" return read_from_memory_address(\n",
|
||||
" self.initial_memory_address + idx * self.block_size\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fcd44a0c-5fca-4fdb-af1b-b09bb3be5bca",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Python's `list` type is internally implemented as an array.\n",
|
||||
"\n",
|
||||
"- What happens when we need to grow the list?\n",
|
||||
"- what does `list.append` do?\n",
|
||||
"- what does `list.insert(0, 0)` (at the beginning) do?\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3503e142-c26f-4598-8240-a11b9397147b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Linked Lists\n",
|
||||
"\n",
|
||||
"An alternative way to store sequential items is by using a linked list.\n",
|
||||
"\n",
|
||||
"Linked lists store individual elements and a pointer to the next element. This means that looking up the Nth element requires traversing the entire list.\n",
|
||||
"\n",
|
||||
"![](https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Singly-linked-list.svg/408px-Singly-linked-list.svg.png)\n",
|
||||
"\n",
|
||||
"Linked lists can grow without bound, each new node can be allocated on the fly."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "cfb1a2af-b065-43cf-b7b0-3bfb046d9d85",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Node:\n",
|
||||
" def __init__(self, value, _next=None):\n",
|
||||
" self.value = value\n",
|
||||
" self.next = _next\n",
|
||||
" self.prev = ..\n",
|
||||
"\n",
|
||||
"class LinkedList:\n",
|
||||
" def __init__(self):\n",
|
||||
" self.root = None\n",
|
||||
"\n",
|
||||
" def add(self, value):\n",
|
||||
" if self.root is None:\n",
|
||||
" # first value: special case\n",
|
||||
" self.root = Node(value)\n",
|
||||
" else:\n",
|
||||
" cur = self.root\n",
|
||||
" # traverse to end of list\n",
|
||||
" while cur.next:\n",
|
||||
" cur = cur.next\n",
|
||||
" # drop a new node at the end of list\n",
|
||||
" cur.next = Node(value)\n",
|
||||
"\n",
|
||||
" def __str__(self):\n",
|
||||
" s = \"\"\n",
|
||||
" cur = self.root\n",
|
||||
" while cur:\n",
|
||||
" s += f\"[{cur.value}] -> \"\n",
|
||||
" cur = cur.next\n",
|
||||
" s += \"END\"\n",
|
||||
" return s"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "2a796778-c06e-4585-b201-07061d25e561",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[1] -> [3] -> [5] -> [7] -> END\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"ll = LinkedList()\n",
|
||||
"ll.add(1)\n",
|
||||
"ll.add(3)\n",
|
||||
"ll.add(5)\n",
|
||||
"ll.add(7)\n",
|
||||
"print(ll)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "99f36edd-93e8-4658-b5cd-41eed7d9b4ce",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Optimizations\n",
|
||||
"\n",
|
||||
"Doubly linked lists, and more complicated internal pointer structures can lead to increased performance at cost of more memory/complexity.\n",
|
||||
"\n",
|
||||
"(Our first memory vs. runtime trade-off)\n",
|
||||
"\n",
|
||||
"`collections.deque` is a doubly linked list implementation in Python.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0bfd80aa-4a8d-465c-9c29-aa1aba55c18c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Linked List vs. Array\n",
|
||||
"\n",
|
||||
"**Array**\n",
|
||||
" \n",
|
||||
"- Lookup: O(1)\n",
|
||||
"- Append: O(1) unless at capacity, then expensive O(n) copy\n",
|
||||
"- Insertion: O(n)\n",
|
||||
"\n",
|
||||
"Requires over-allocation of memory to gain efficiency.\n",
|
||||
"\n",
|
||||
"**Linked List** \n",
|
||||
" \n",
|
||||
"- Lookup: O(n)\n",
|
||||
"- Append: O(1)\n",
|
||||
"- Insertion: O(n)\n",
|
||||
"\n",
|
||||
"Requires pointer/node structure to gain efficiency."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9465bc5b-8d44-43bf-83c6-5ede55f722f5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Stack\n",
|
||||
"\n",
|
||||
"A stack is a last-in-first-out (LIFO) data structure that needs to primarily serve two operations: push, and pop.\n",
|
||||
"\n",
|
||||
"Both should be O(1).\n",
|
||||
"\n",
|
||||
"### Usage\n",
|
||||
"\n",
|
||||
"- Undo/Redo\n",
|
||||
"- Analogy: stack of plates -- add to/take from the top\n",
|
||||
"- Call Stacks\n",
|
||||
"\n",
|
||||
"Sometimes when we're writing code we talk about \"the stack\", which is the call stack of functions we're in & their scopes.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"\n",
|
||||
"def f():\n",
|
||||
" ...\n",
|
||||
" \n",
|
||||
" \n",
|
||||
"def g():\n",
|
||||
" if ...:\n",
|
||||
" f()\n",
|
||||
" else:\n",
|
||||
" ...\n",
|
||||
"\n",
|
||||
"def h():\n",
|
||||
" y = g()\n",
|
||||
" ...\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"When we call h(), it is added to the call stack, then g is added, and f is added on top. We return from these functions in LIFO order, f() exits, then g(), then h().\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "6c73e9f9-17e4-4057-b5fb-d169d0db9b96",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Stack:\n",
|
||||
" def __init__(self):\n",
|
||||
" self._data = []\n",
|
||||
"\n",
|
||||
" def push(self, item):\n",
|
||||
" # remember: adding/removing at the end of the list is faster than the front\n",
|
||||
" self._data.append(item)\n",
|
||||
"\n",
|
||||
" def pop(self):\n",
|
||||
" return self._data.pop()\n",
|
||||
"\n",
|
||||
" def __len__(self):\n",
|
||||
" return len(self._data)\n",
|
||||
"\n",
|
||||
" def __str__(self):\n",
|
||||
" return \" TOP -> \" + \"\\n \".join(\n",
|
||||
" f\"[ {item} ]\" for item in reversed(self._data)\n",
|
||||
" )\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "1db244c8-9168-4c19-a73c-53a20c48485a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "NameError",
|
||||
"evalue": "name 'Stack' 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[6], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m s \u001b[38;5;241m=\u001b[39m \u001b[43mStack\u001b[49m()\n\u001b[1;32m 2\u001b[0m s\u001b[38;5;241m.\u001b[39mpush(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mh()\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124mcalled h()\u001b[39m\u001b[38;5;124m'\u001b[39m)\n",
|
||||
"\u001b[0;31mNameError\u001b[0m: name 'Stack' is not defined"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"s = Stack()\n",
|
||||
"s.push(\"h()\")\n",
|
||||
"print('\\ncalled h()')\n",
|
||||
"print(s)\n",
|
||||
"print('\\nh called g()')\n",
|
||||
"s.push(\"g()\")\n",
|
||||
"print(s)\n",
|
||||
"print('\\ng called f()')\n",
|
||||
"s.push(\"f()\")\n",
|
||||
"print(s)\n",
|
||||
"print(\"\\nexited\", s.pop())\n",
|
||||
"print(s)\n",
|
||||
"print(\"\\nexited\", s.pop())\n",
|
||||
"print(s)\n",
|
||||
"print(\"\\nexited\", s.pop())\n",
|
||||
"print(s)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "05fefd4e-4701-437b-b7e8-e5566e753708",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Queue\n",
|
||||
"\n",
|
||||
"A queue is a first-in-first-out (FIFO) data structure that adds items to one end, and removes them from the other.\n",
|
||||
"\n",
|
||||
"We see queues all over the place in everyday life and computing. Most resources are accessed on a FIFO basis."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "4525594e-070b-4bcb-b4c7-a3641f514b2d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class ArrayQueue:\n",
|
||||
" def __init__(self, _iterable=None):\n",
|
||||
" if _iterable:\n",
|
||||
" self._data = list(_iterable)\n",
|
||||
" else:\n",
|
||||
" self._data = []\n",
|
||||
"\n",
|
||||
" def push(self, item):\n",
|
||||
" # adding to the end of the list is faster than the front\n",
|
||||
" self._data.append(item)\n",
|
||||
"\n",
|
||||
" def pop(self):\n",
|
||||
" # only change from `Stack` is we remove from the other end\n",
|
||||
" # this can be slower, why?\n",
|
||||
" return self._data.pop(0)\n",
|
||||
"\n",
|
||||
" def __len__(self):\n",
|
||||
" return len(self._data)\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return \" TOP -> \" + \"\\n \".join(\n",
|
||||
" f\"[ {item} ]\" for item in reversed(self._data)\n",
|
||||
" )\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "20c843b5-9c64-45cb-af77-514b680cbd9c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from collections import deque\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class DequeQueue:\n",
|
||||
" def __init__(self, _iterable=None):\n",
|
||||
" if _iterable:\n",
|
||||
" self._data = deque(_iterable)\n",
|
||||
" else:\n",
|
||||
" self._data = deque()\n",
|
||||
"\n",
|
||||
" def push(self, item):\n",
|
||||
" self._data.append(item)\n",
|
||||
"\n",
|
||||
" def pop(self):\n",
|
||||
" return self._data.popleft()\n",
|
||||
"\n",
|
||||
" def __len__(self):\n",
|
||||
" return len(self._data)\n",
|
||||
"\n",
|
||||
" def __repr__(self):\n",
|
||||
" return \" TOP -> \" + \"\\n \".join(\n",
|
||||
" f\"[ {item} ]\" for item in reversed(self._data)\n",
|
||||
" )\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3af2e4e7-e600-4201-859b-9b36751a5247",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Performance Testing\n",
|
||||
"\n",
|
||||
"We can try to measure performance something takes by measuring how much time has passed.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"before = time.time()\n",
|
||||
"# do something\n",
|
||||
"after = time.time()\n",
|
||||
"elapsed = before - after\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Issue is that in practice, times involved are miniscule, and other events on the system will overshadow differences."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "a414509d-84bb-4ae7-a105-2c6b9dcb7406",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import time\n",
|
||||
"\n",
|
||||
"def print_elapsed(func):\n",
|
||||
" def newfunc(*args, **kwargs):\n",
|
||||
" before = time.time()\n",
|
||||
" retval = func(*args, **kwargs)\n",
|
||||
" elapsed = time.time() - before\n",
|
||||
" print(f\"Took {elapsed} sec to run {func.__name__}\")\n",
|
||||
"\n",
|
||||
" return newfunc\n",
|
||||
"\n",
|
||||
"@print_elapsed\n",
|
||||
"def testfunc(QueueCls):\n",
|
||||
" queue = QueueCls()\n",
|
||||
" for item in range(1000):\n",
|
||||
" queue.push(item)\n",
|
||||
" while queue:\n",
|
||||
" queue.pop()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "f1842168-b12d-4d1c-a004-10614904f3f2",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Took 0.0012509822845458984 sec to run testfunc\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"testfunc(ArrayQueue)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "19a3b107-da59-40f3-bafb-70160747fb53",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Took 0.001255035400390625 sec to run testfunc\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"testfunc(DequeQueue)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0cd093da-0a2c-4adb-96b8-bd56a874f6f2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The differences are just too small to be sure. We need to run our code many more times.\n",
|
||||
"\n",
|
||||
"Python has a built in module for this, `timeit`.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import timeit\n",
|
||||
"\n",
|
||||
"timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)\n",
|
||||
"\n",
|
||||
"# for more: https://docs.python.org/3/library/timeit.html\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "93010cc5-55c9-4308-b0d0-8fac623f2c55",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"1000000x ArrayQueue.push, took 0.11357445899921004\n",
|
||||
"1000000x DequeQueue.push, took 0.06381245900047361\n",
|
||||
"DequeQueue is 43.814% less time\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import timeit\n",
|
||||
"\n",
|
||||
"number = 1_000_000\n",
|
||||
"\n",
|
||||
"elapsed = timeit.timeit(\n",
|
||||
" \"queue.push(1)\",\n",
|
||||
" setup=\"queue = QueueCls()\",\n",
|
||||
" globals={\"QueueCls\": ArrayQueue},\n",
|
||||
" number=number,\n",
|
||||
")\n",
|
||||
"elapsed2 = timeit.timeit(\n",
|
||||
" \"queue.push(1)\",\n",
|
||||
" setup=\"queue = QueueCls()\",\n",
|
||||
" globals={\"QueueCls\": DequeQueue},\n",
|
||||
" number=number,\n",
|
||||
")\n",
|
||||
"print(f\"{number}x ArrayQueue.push, took\", elapsed)\n",
|
||||
"print(f\"{number}x DequeQueue.push, took\", elapsed2)\n",
|
||||
"print(f\"DequeQueue is {(elapsed-elapsed2) / elapsed * 100:.3f}% less time\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "f40f7691-599c-49f9-8f08-30aa14c1e90a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"10000x ArrayQueue.pop, took 16.82198095900094\n",
|
||||
"10000x DequeQueue.pop, took 0.0005862910002178978\n",
|
||||
"DequeQueue is 99.997% less time\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"number = 10_000\n",
|
||||
"\n",
|
||||
"elapsed = timeit.timeit(\n",
|
||||
" \"queue.pop()\",\n",
|
||||
" setup=\"queue = QueueCls([0] * 10000000)\",\n",
|
||||
" globals={\"QueueCls\": ArrayQueue},\n",
|
||||
" number=number,\n",
|
||||
")\n",
|
||||
"elapsed2 = timeit.timeit(\n",
|
||||
" \"queue.pop()\",\n",
|
||||
" setup=\"queue = QueueCls([0] * 10000000)\",\n",
|
||||
" globals={\"QueueCls\": DequeQueue},\n",
|
||||
" number=number,\n",
|
||||
")\n",
|
||||
"print(f\"{number}x ArrayQueue.pop, took\", elapsed)\n",
|
||||
"print(f\"{number}x DequeQueue.pop, took\", elapsed2)\n",
|
||||
"print(f\"DequeQueue is {(elapsed-elapsed2) / elapsed * 100:.3f}% less time\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "4333f0dd-846e-44fa-8aa0-9c3d883c165e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"58.76708083400081"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"timeit.timeit(\"''.join(['a', 'b', 'c', 'd'])\", number=1000000000)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "5a4a6e0d-0e02-42bf-8d53-06b09ce1a5dd",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"5.945709666997573"
|
||||
]
|
||||
},
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"timeit.timeit(\"d = ('apple'*5) + 'banana' + 'c' + 'd'\", number=1000000000)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b20fc917-73d2-4378-ae0a-a2119883efa3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Queue Performance\n",
|
||||
"\n",
|
||||
"| Operation | ArrayQueue | DequeQueue |\n",
|
||||
"| --------- | ---------- | ---------- |\n",
|
||||
"| push | O(1) | O(1) |\n",
|
||||
"| pop | O(n) | O(1) |\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c44f9af3-4a0a-4dad-8bf6-4ec3ecc7d3f1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"\n",
|
||||
"For a Stack, an array or linked list can both give O(1) performance.\n",
|
||||
"\n",
|
||||
"For a Queue, a (doubly) linked list is necessary.\n",
|
||||
"\n",
|
||||
"But arrays are superior for indexing operations. And *typical* code indexes list far more than it appends/inserts. Depending on your needs Python's `list` implementation may not be the optimal data structure."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d6c3fd9d-12a3-49a2-aba4-257d8a6eb829",
|
||||
"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.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
440
16.trees-graphs-tries.ipynb
Normal file
440
16.trees-graphs-tries.ipynb
Normal file
@ -0,0 +1,440 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f37ff61d-dfe1-4b65-a74d-efe317bbfade",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Data Structures: Trees, Graphs, and Tries"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c12455f1-b6e7-4822-8b20-0da02e8e7a11",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We saw that linked lists use nodes linked in a linear fashion.\n",
|
||||
"\n",
|
||||
"Each node had a \"next\" (and possibly a reference to \"prev\").\n",
|
||||
"\n",
|
||||
"We can use this same idea with additional links to create **Trees**.\n",
|
||||
"\n",
|
||||
"We'll start with a classic **binary search tree**.\n",
|
||||
"\n",
|
||||
"Each node has a value, and up to two children, \"left\" and \"right\".\n",
|
||||
"\n",
|
||||
"Data is stored in the tree such that when a new node is added, if it is less than the current value of a node, it should be stored to the left, and if it is greater, it should be stored to the right.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "012f2a24-f0cc-47ef-a572-3c0825f27850",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Node:\n",
|
||||
" def __init__(self, value, left=None, right=None):\n",
|
||||
" self.value = value\n",
|
||||
" self.left = left\n",
|
||||
" self.right = right\n",
|
||||
"\n",
|
||||
" def __str__(self):\n",
|
||||
" return f\"({self.value}, {self.left}, {self.right})\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class BST:\n",
|
||||
" def __init__(self, iterable=None):\n",
|
||||
" self.root = None\n",
|
||||
" if iterable:\n",
|
||||
" for item in iterable:\n",
|
||||
" self.add_item(item)\n",
|
||||
"\n",
|
||||
" def add_item(self, newval):\n",
|
||||
" # special case: first item\n",
|
||||
" if self.root is None:\n",
|
||||
" self.root = Node(newval)\n",
|
||||
" else:\n",
|
||||
" parent = self.root\n",
|
||||
" # traverse until we find room in the tree\n",
|
||||
" while True:\n",
|
||||
" if newval < parent.value:\n",
|
||||
" if parent.left:\n",
|
||||
" parent = parent.left\n",
|
||||
" else:\n",
|
||||
" parent.left = Node(newval)\n",
|
||||
" break\n",
|
||||
" else:\n",
|
||||
" if parent.right:\n",
|
||||
" parent = parent.right\n",
|
||||
" else:\n",
|
||||
" parent.right = Node(newval)\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def print_infix(node):\n",
|
||||
" \"\"\"prints items in sorted order\"\"\"\n",
|
||||
" if node.left:\n",
|
||||
" print_infix(node.left)\n",
|
||||
" print(node.value)\n",
|
||||
" if node.right:\n",
|
||||
" print_infix(node.right)\n",
|
||||
" "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c833bb06-4b02-4f50-bab9-ab1d30092144",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Tree traversal is inherently recursive, so we'll use a recursive function to print the tree in sorted order.\n",
|
||||
"\n",
|
||||
"Most tree algorithms will operate on the left & right subtrees the same way, so we can write a recursive function that takes a node and calls itself on the left & right subtrees."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "4f652851-2fbd-42c1-adb3-cb352657bb5a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Bear\n",
|
||||
"Fox\n",
|
||||
"Rabbit\n",
|
||||
"Raccoon\n",
|
||||
"Wolf\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"tree = BST()\n",
|
||||
"tree.add_item(\"Fox\")\n",
|
||||
"tree.add_item(\"Wolf\")\n",
|
||||
"tree.add_item(\"Bear\")\n",
|
||||
"tree.add_item(\"Raccoon\")\n",
|
||||
"tree.add_item(\"Rabbit\")\n",
|
||||
"print_infix(tree.root)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "44e92462-532b-4340-8c9b-52314870677f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Aside: defaultdict\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# common pattern:\n",
|
||||
"if key not in dct:\n",
|
||||
" dct[key] = []\n",
|
||||
"dct[key].append(element)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"We can instead use `collections.defaultdict`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "a06805c2-75ae-46e3-9916-f4ee8cca6080",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{1, 2, 3}\n",
|
||||
"defaultdict(<function <lambda> at 0x111069120>, {'newkey': {1, 2, 3}})\n",
|
||||
"defaultdict(<function <lambda> at 0x111069120>, {'newkey': {1, 2, 3, 4}})\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from collections import defaultdict\n",
|
||||
"\n",
|
||||
"# give defaultdict a function that it will use to generate missing keys\n",
|
||||
"dd = defaultdict(lambda: {1, 2, 3})\n",
|
||||
"\n",
|
||||
"print(dd[\"newkey\"])\n",
|
||||
"print(dd)\n",
|
||||
"\n",
|
||||
"dd[\"newkey\"].add(4) # can add to set without ensuring it exists\n",
|
||||
"print(dd)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ba2d9950-e5cf-4d11-9307-f1fa37f01e67",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Graphs\n",
|
||||
"\n",
|
||||
"![](https://www.simplilearn.com/ice9/free_resources_article_thumb/Graph%20Data%20Structure%20-%20Soni/what-is-graphs-in-data-structure.png)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "323a6e33-76b7-41b7-97b9-e4dfa04d6bb4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Graph:\n",
|
||||
" def __init__(self):\n",
|
||||
" # create a dictionary where every string maps to a set of strings\n",
|
||||
" self.edges = defaultdict(set)\n",
|
||||
"\n",
|
||||
" def add_edge(self, node1, node2):\n",
|
||||
" # add in both directions, could alter for directed graph\n",
|
||||
" self.edges[node1].add(node2)\n",
|
||||
" self.edges[node2].add(node1)\n",
|
||||
"\n",
|
||||
" def find_path(self, from_node, to_node, seen=None):\n",
|
||||
" if not seen:\n",
|
||||
" seen = set()\n",
|
||||
"\n",
|
||||
" if to_node in self.edges[from_node]:\n",
|
||||
" return (from_node, to_node)\n",
|
||||
" else:\n",
|
||||
" for sibling in self.edges[from_node] - seen:\n",
|
||||
" return (from_node,) + self.find_path(\n",
|
||||
" sibling, to_node, seen | set(sibling)\n",
|
||||
" )\n",
|
||||
" # return self.find_path("
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "867f5186-e308-4d2f-9766-713ecb352f99",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"('A', 'D', 'B')"
|
||||
]
|
||||
},
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"g = Graph()\n",
|
||||
"g.add_edge(\"A\", \"D\")\n",
|
||||
"g.add_edge(\"B\", \"D\")\n",
|
||||
"g.find_path(\"A\", \"B\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "a9acaa28-8a24-41c5-86c0-4342365533f6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"('A', 'B', 'A', 'D', 'E')"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"g = Graph()\n",
|
||||
"g.add_edge(\"A\", \"B\")\n",
|
||||
"g.add_edge(\"B\", \"C\")\n",
|
||||
"g.add_edge(\"C\", \"D\")\n",
|
||||
"g.add_edge(\"D\", \"E\")\n",
|
||||
"g.add_edge(\"A\", \"D\")\n",
|
||||
"g.find_path(\"A\", \"E\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "615230a9-5f7c-47c9-9d5e-83d37081bc47",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Discussion\n",
|
||||
"\n",
|
||||
"* Graphs & Trees in the real world?\n",
|
||||
"* Alternate implementations?\n",
|
||||
" * NetworkX"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "45d51cd1-9d2b-40dd-95b2-f51f11b49b9e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Tries\n",
|
||||
"\n",
|
||||
"Usually pronounced \"try\" to differentiate it from trees.\n",
|
||||
"\n",
|
||||
"A **trie** is a data structure that stores data associated with string keys similar to a dictionary in many ways. (Python `dict`s are a different data structure: **hash tables**.)\n",
|
||||
"\n",
|
||||
"A **trie** is a specialized data structure, particularly useful for partial matching of strings. The way the data is stored enables efficient lookup of all strings that start with a given prefix, as well as \"fuzzy search\" where some characters don't match.\n",
|
||||
"\n",
|
||||
"Each node in a **trie** contains:\n",
|
||||
"\n",
|
||||
"- an fixed-size array of children\n",
|
||||
"- a value\n",
|
||||
"\n",
|
||||
"Let's imagine a simplified version of a **trie** that can only store string keys with the letters \"a\", \"b\", \"c\", and \"d\".\n",
|
||||
"\n",
|
||||
"So keys \"a\", \"ba\", \"dddddd\", and \"abcdabcdaabcad\" would all be valid.\n",
|
||||
"\n",
|
||||
"Now, instead of `linked_list.next` or `tree_node.left`, we will have four children, so we'll store them in a tuple:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"id": "1ed75b91-54fe-4650-965d-ef26507788b9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"class TrieNode:\n",
|
||||
" def __init__(self, value=None):\n",
|
||||
" self.value = value\n",
|
||||
" self.children = [None, None, None, None]\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4ad2dec4-dc42-48bd-a144-d5c61d60dfdb",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Notice that we **do not store the key**!\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"trie = Trie()\n",
|
||||
"trie[\"a\"] = 1\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Represents a tree with a single key \"a\". The node \"X\" is the 0th child of the root node. It would have no children set, and a value of `1`.\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
" root\n",
|
||||
" / \\\\\\\n",
|
||||
" X\n",
|
||||
"//\\\\\n",
|
||||
"```\n",
|
||||
"Let's look at a trie where someone has also set `trie[\"aba\"] = 100`\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
" root\n",
|
||||
" / \\\\\\\n",
|
||||
" X \n",
|
||||
" /|\\\\\n",
|
||||
" Y\n",
|
||||
" /\\\\\\\n",
|
||||
" Z \n",
|
||||
" //\\\\\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Each node has four children, the 0th child being associated with the value \"a\", the 1st with \"b\", and so on.\n",
|
||||
"\n",
|
||||
"- X is the same as before `value=1`. It now has a child node \"Y\" in 1st position, associated with \"b\". \n",
|
||||
"- Y has no `value` set, because it only exists to build out the tree in this case. It has a child at \"a\" position (0).\n",
|
||||
"- Z is at a terminal position and would have `value=100`. Since the path from the root is \"aba\" that is the key associated with the value."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3c397fb5-0503-4d8e-a13d-58b6d5cd6943",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Lookup Algorithm\n",
|
||||
"\n",
|
||||
"Traversing the tree is done by a simple recursive algorithm:\n",
|
||||
"\n",
|
||||
"- if there are more letters in the key: convert the next one to an index and traverse to that child node\n",
|
||||
"- if there are no more letters: the current node is the destination\n",
|
||||
"\n",
|
||||
"The correct behavior when encountering a child node that does not (yet) exist depends on the nature of the traversal:\n",
|
||||
"\n",
|
||||
"In a lookup (such as `__getitem__`) the key in question must not be in the **trie**.\n",
|
||||
"If a value was being set, the node should be created.\n",
|
||||
"\n",
|
||||
"### Note/Project Hint\n",
|
||||
"\n",
|
||||
"`value=None` will create problems in practice, because you should be able to set `trie[\"abc\"] = None` and not have it treat it as if the data was deleted.\n",
|
||||
"\n",
|
||||
"Instead, you will probably want to use different values for unset variables. It is common to make a \"sentinel\" class for this, a class that is used to create a unique value (like `None` being the sole instance of `NoneType`.).\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class DefaultColor:\n",
|
||||
" \"\"\" Used as a sentinel class. \"\"\"\n",
|
||||
"\n",
|
||||
"def set_background(color=DefaultColor):\n",
|
||||
" \"\"\"\n",
|
||||
" This function exists to set the background color.\n",
|
||||
" (In reality, to demonstrate a time when you might treat None and an unset value differently.)\n",
|
||||
" \n",
|
||||
" If color is set to None, the background will be transparent.\n",
|
||||
" If color is not set, the background will default to the user's choice.\n",
|
||||
" \"\"\"\n",
|
||||
" if color is DefaultColor:\n",
|
||||
" ...\n",
|
||||
"```\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4aef9799-2f13-4c7c-ae62-ac8e6ed22ca3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Trie Complexity\n",
|
||||
"\n",
|
||||
"Trie traversal complexity is `O(m)` where **m** is the length of the key strings. \n",
|
||||
"\n",
|
||||
"This in practice would likely be much lower than **n**, the number of words in the data.\n",
|
||||
"\n",
|
||||
"### Discussion\n",
|
||||
"\n",
|
||||
"- How would prefix lookup work?\n",
|
||||
"- Wildcards?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0939902d-b50b-4073-92ab-4df03bc1b6fb",
|
||||
"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.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
298
17.ecosystem.ipynb
Normal file
298
17.ecosystem.ipynb
Normal file
@ -0,0 +1,298 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b4869e5b-a600-4285-8879-5053a13d6e6f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Python Ecosystem\n",
|
||||
"\n",
|
||||
"One of the reason's for Python's early success was its \"batteries included\" philosophy.\n",
|
||||
"\n",
|
||||
"If you remember being a kid and getting a new toy, only to have to purchase (or charge) its batteries before playing-- the analogy here is that Python comes with everything you need to play (be productive) out of the box.\n",
|
||||
"\n",
|
||||
"We've seen this with some built in modules:\n",
|
||||
"\n",
|
||||
"- datetime\n",
|
||||
"- math\n",
|
||||
"- csv\n",
|
||||
"- json\n",
|
||||
"- functools\n",
|
||||
"- itertools\n",
|
||||
"- collections\n",
|
||||
"- abc\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e4385a75-4d33-4de2-a840-006dc06fdc7b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The standard library contains tools for common (and less-common) file types, data structures, dealing with data from the web, a simple UI toolkit, and much more:\n",
|
||||
"\n",
|
||||
"<https://docs.python.org/3/library/index.html>\n",
|
||||
"\n",
|
||||
"These modules are written in Python or C, and distributed with Python itself. \n",
|
||||
"\n",
|
||||
"The standard library is great for many things but in practice it has a few shortcomings:\n",
|
||||
"\n",
|
||||
"- can't possibly include *everything*\n",
|
||||
"- typically only one way of doing things, and if an alternate approach is needed, an alternate library should be (example: streaming JSON)\n",
|
||||
"- once a package is in standard library it is in effect *frozen* due to Python's strict backwards compatibility rules"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b3758d4b-2b85-4d69-80c1-160d16bd4ba3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Beyond the Standard Library\n",
|
||||
"\n",
|
||||
"It is helpful to have a wider ecosystem that all Python developers can share-- enter the Python Package Index or PyPI (typically pronounced pie-pee-eye to avoid confusing with PyPy pronounced pie-pie).\n",
|
||||
"\n",
|
||||
"https://pypi.org\n",
|
||||
"\n",
|
||||
"Over half a million projects released on PyPI, with billions of downloads a day.\n",
|
||||
"\n",
|
||||
"We've seen packages that come from PyPI:\n",
|
||||
"\n",
|
||||
"- rich\n",
|
||||
"- httpx\n",
|
||||
"- pandas\n",
|
||||
"- polars\n",
|
||||
"- networkx\n",
|
||||
"- matplotlib\n",
|
||||
"- altair\n",
|
||||
"- Pillow\n",
|
||||
"- Flask\n",
|
||||
"- Django"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f4a25d8b-d3c0-462b-a87a-ee34b98e8663",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Important Note: Anyone can publish to PyPI\n",
|
||||
"\n",
|
||||
"Installing a package means trusting its authors to some extent. \n",
|
||||
"\n",
|
||||
"Packages I ask you to install are packages I trust, and which have established reputations & teams.\n",
|
||||
"\n",
|
||||
"If you find a small package you should be mindful of the fact that letting someone run code on your system means letting that person do whatever their code does. \n",
|
||||
"\n",
|
||||
"If in doubt:\n",
|
||||
"- look for signs of activity on GitHub/etc.: a popular library with dozens of tutorials is one thing -- an obscure library only one person used may also be fine, but worth a bit of vetting\n",
|
||||
"- look at the source code!\n",
|
||||
"- ask someone! (James, TAs, etc.)\n",
|
||||
"\n",
|
||||
"### Licensing\n",
|
||||
"\n",
|
||||
"Code that is published & open source comes with a license, a set of rules saying what you may and may not do with it. Typically this prohibits redistribution of the work without the license, but in some cases may mean that your own work needs to be open source to use it. **Using open source code without following the license is plagarism/theft and can come with serious consequences here and in any workplace since your employer would carry the legal burden.**\n",
|
||||
"\n",
|
||||
"Make sure that the code that you are using is under a license that allows you to use it in the environment that you are in. That isn't much of an issue here in class, but in companies you may not be able to use certain licenses. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "debb1e93-d3ce-4b54-ae45-0b470ba39242",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Python's Worst Flaw\n",
|
||||
"\n",
|
||||
"A key part of Python's general philosophy is that there should be an obvious way to do things. It is generally acknowledged that we have fallen short when it comes to package management. \n",
|
||||
"\n",
|
||||
"The situation is improving, and you have already been using the latest & greatest tool. But as you venture out into the wider world of packages, you'll notice some rough edges for sure.\n",
|
||||
"\n",
|
||||
"When you look at instructions, some libraries will tell you to:\n",
|
||||
"\n",
|
||||
"- `pip install matplotlib`\n",
|
||||
"\n",
|
||||
"You may also have used `conda` before, and done something similar.\n",
|
||||
"\n",
|
||||
"In this class, we've been using `uv`, and you may also encounter:\n",
|
||||
"\n",
|
||||
"- `pdm`\n",
|
||||
"- `poetry`\n",
|
||||
"- `pip-compile`\n",
|
||||
"- `pipx`\n",
|
||||
"- `pip-tools`\n",
|
||||
"\n",
|
||||
"And probably a dozen other solutions to installing & managing packages.\n",
|
||||
"\n",
|
||||
"*What's going on?*\n",
|
||||
"\n",
|
||||
"### How Python Packages Work\n",
|
||||
"\n",
|
||||
"Recall that python packages are just directories. When you install a package you are getting something that resembles:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"baking-pkg\n",
|
||||
"├── baking\n",
|
||||
"│ ├── __init__.py\n",
|
||||
"│ ├── cli.py\n",
|
||||
"│ ├── ingredients.py\n",
|
||||
"│ ├── sizes.py\n",
|
||||
"│ ├── units.py\n",
|
||||
"│ └── utils.py\n",
|
||||
"├── LICENSE\n",
|
||||
"├── README.md\n",
|
||||
"└── tests\n",
|
||||
" ├── test_baking.py\n",
|
||||
" ├── test_units.py\n",
|
||||
" └── test_utils.py\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"If I gave you these files and you put them on your desktop, you would find that you could only use them if you were in the same directory. That is if you put your own files in `baking-pkg` you would be able to `import baking` but otherwise it would fail.\n",
|
||||
"\n",
|
||||
"When you type an `import` statement, Python uses an **environment variable** a variable set at the operating system level, not specific to Python named `PYTHONPATH` to look up what directories it should search.\n",
|
||||
"\n",
|
||||
"This variable contains a list of directories, which might resemble:\n",
|
||||
"\n",
|
||||
"- /home/user/james/.poetry/global/\n",
|
||||
"- /usr/lib/python3.10\n",
|
||||
"- /usr/lib/python3.10/lib-dynload\n",
|
||||
"- /usr/local/lib/python3.10/dist-packages\n",
|
||||
"- /usr/lib/python3/dist-packages\n",
|
||||
"- /home/user/james/.pipx/ruff/\n",
|
||||
"- /home/user/james/.pipx/jupyter/\n",
|
||||
"\n",
|
||||
"These directories are searched in order, so if I have a `math` library in `/home/user/james/.poetry/global/` it will supercede the built in math library in `/usr/lib/python3.10/`.\n",
|
||||
"\n",
|
||||
"This means that can only have one library of a given name that is importable."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dbf0e9aa-3c9a-457a-a2c6-6fdde95ca2cb",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Version Conflicts\n",
|
||||
"\n",
|
||||
"In practice though, you might need to have multiple copies of a library installed on your system, imagine the following:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Project 1 (MPCS 51042)**\n",
|
||||
"- polars==1.14\n",
|
||||
"- seaborn==2.0\n",
|
||||
" - matplotlib==3.0\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Project 2 (MPCS 52000)**\n",
|
||||
"- polars==0.44\n",
|
||||
"- matplotlib==2.0\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Project 3 (Work)**\n",
|
||||
"- altair==5.0\n",
|
||||
"- customlibrary\n",
|
||||
" - matplotlib==2.4\n",
|
||||
" \n",
|
||||
"Your system would need 3 versions of `matplotlib` to be able to correctly run the code in question."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5e99e59c-f19f-4312-b842-6862eacc64a7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Installing Packages (the wrong way)\n",
|
||||
"\n",
|
||||
"If you use `pip` on its own, each time you install a set of packages, it will uninstall conflicts & replace the version with the latest.\n",
|
||||
"\n",
|
||||
"By default `pip` installs to the `/usr/lib/python3.10/dist-packages/` directory (or equivalent), but wherever it installs on your PYTHONPATH would have the same issue. We can only have one of a package installed at a time."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9a69a927-dffb-46e3-9e86-1e09fbe013bd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Virtualenvs\n",
|
||||
"\n",
|
||||
"For this reason, Python has the concept of `virtualenvs`. These are directories of Python packages that are meant to only be added to PYTHONPATH when a given project is being used.\n",
|
||||
"\n",
|
||||
"If we installed all of the packages for our three projects to three different directories:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
".\n",
|
||||
"├── proj1-venv\n",
|
||||
"│ ├── matplotlib # v3.0\n",
|
||||
"│ ├── polars\n",
|
||||
"│ └── seaborn\n",
|
||||
"├── proj2-venv\n",
|
||||
"│ ├── matplotlib # v2.0\n",
|
||||
"│ └── polars\n",
|
||||
"└── proj3-venv\n",
|
||||
" ├── altair\n",
|
||||
" ├── customlibrary\n",
|
||||
" └── matplotlib # v2.4\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Now we can add the correct `venv` directory to our PYTHONPATH before running the appropriate command.\n",
|
||||
"\n",
|
||||
"This is what `venv` does for us:\n",
|
||||
"<https://docs.python.org/3/library/venv.html>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9abe42e4-3a2a-417d-996b-e25fe0db2ce6",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## `uv` (and other package managers)\n",
|
||||
"\n",
|
||||
"In practice, managing a venv can be tedious and error-prone, which is why a suite of tools exists to help manage them for you.\n",
|
||||
"\n",
|
||||
"In this class we have opted for `uv`, among the newest of these tools which (IMO) is the easiest to use yet.\n",
|
||||
"\n",
|
||||
"`uv` demo:\n",
|
||||
"- uv creates `.venv`\n",
|
||||
"- `uv add` updates lockfile and venv\n",
|
||||
"- `uv run` ensures that the correct venv is activated before Python starts\n",
|
||||
"\n",
|
||||
"https://mpcs51042.netlify.app/guides/uv/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "85c23bfc-d1b5-4941-acf2-f415fa2f7a9d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Recommendation: Always start new projects with `uv init` (or similar!)\n",
|
||||
"\n",
|
||||
"Never use `pip` or `venv` directly!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1be81171-4c6c-432d-8a7e-d39d4bf601ef",
|
||||
"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.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
485
18.testing.ipynb
Normal file
485
18.testing.ipynb
Normal file
@ -0,0 +1,485 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Testing\n",
|
||||
"\n",
|
||||
"As you've no doubt discovered through working on PAs, tests are useful for ensuring that code works as expected.\n",
|
||||
"\n",
|
||||
"We break our code into functions and classes to encapsulate functionality that we intend to reuse.\n",
|
||||
"These boundaries also provide a natural place to test our code.\n",
|
||||
"\n",
|
||||
"If you only have one big function that does everything, it can be difficult to test:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"\n",
|
||||
"def advance_all_students_with_passing_grades():\n",
|
||||
" conn = sqlite3.connect('students.db')\n",
|
||||
" c = conn.cursor()\n",
|
||||
" c.execute('''\n",
|
||||
" SELECT student.id, avg(class.grade) as average \n",
|
||||
" FROM students JOIN classes ON students.id = classes.student_id\n",
|
||||
" GROUP BY student.id HAVING average >= 70\n",
|
||||
" ''')\n",
|
||||
" students = c.fetchall()\n",
|
||||
" for student in students:\n",
|
||||
" c.execute('UPDATE student_enrollment SET grade = grade + 1 WHERE student_id = ?', (student[0],))\n",
|
||||
" conn.commit()\n",
|
||||
" conn.close()\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"How would you test this function? You'd need to have a database with a specific set of data in it and then run the function and check that the data was updated as expected.\n",
|
||||
"\n",
|
||||
"If you break the function up into smaller functions, you can test each function in isolation:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"\n",
|
||||
"def get_students(conn, grade_threshold=70):\n",
|
||||
" ...\n",
|
||||
"\n",
|
||||
"def advance_student(conn, student):\n",
|
||||
" ...\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Now you can test each function in isolation.\n",
|
||||
"\n",
|
||||
"By having the function take parameters, you can also test the function with different inputs.\n",
|
||||
"\n",
|
||||
"It is also possible to test the function with a mock database connection that doesn't actually connect to a database but provides the same interface.\n",
|
||||
"\n",
|
||||
"This is called \"mocking\" and is a useful technique for testing code that interacts with external systems.\n",
|
||||
"\n",
|
||||
"## `pytest`\n",
|
||||
"\n",
|
||||
"`pytest` is a popular testing framework for Python, and the one we've been using in class.\n",
|
||||
"\n",
|
||||
"It is easy to use and provides a lot of useful features. Python has a built in `unittest` module, but it is more verbose and less flexible.\n",
|
||||
"\n",
|
||||
"`pytest` provides both a command line tool `pytest`, which you've been using, and a library that you can use to help you write tests.\n",
|
||||
"\n",
|
||||
"## `pytest` command line tool\n",
|
||||
"\n",
|
||||
"When you run `pytest`, it will look for files named `test_*.py` in the current directory and its subdirectories. It will then run any functions in those files that start with `test_`.\n",
|
||||
"\n",
|
||||
"If you take a look at any PA, you'll see that there are files named `test_*.py` in the `tests` directory. This is a common convention, but you can also place the files in other directories.\n",
|
||||
"\n",
|
||||
"Within each `test_module1.py` file, there are functions that start with `test_`. These are the tests that `pytest` will run. You can include other functions in the file as helper functions, but they won't be run by `pytest`.\n",
|
||||
"\n",
|
||||
"### Simple Example\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# my_module.py\n",
|
||||
"from collections import namedtuple\n",
|
||||
"\n",
|
||||
"Point = namedtuple('Point', ['x', 'y'])\n",
|
||||
"\n",
|
||||
"def circle_contains(radius: float, center: Point, point: Point):\n",
|
||||
" return (point.x - center.x) ** 2 + (point.y - center.y) ** 2 <= radius ** 2\n",
|
||||
"\n",
|
||||
"def points_within(radius: float, center: Point, points: list[Point]):\n",
|
||||
" \"\"\" Find all points within a circle. \"\"\"\n",
|
||||
" return [point for point in points if circle_contains(radius, center, point)]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# test_my_module.py\n",
|
||||
"\n",
|
||||
"from my_module import circle_contains, points_within\n",
|
||||
"\n",
|
||||
"origin = Point(0, 0)\n",
|
||||
"\n",
|
||||
"def test_circle_contains():\n",
|
||||
" # centered at origin, radius 1\n",
|
||||
" result = circle_contains(1, origin, origin)\n",
|
||||
" assert result\n",
|
||||
" assert circle_contains(1, origin, Point(.5, .5)), \"circle should contain 0.5, 0.5\"\n",
|
||||
"\n",
|
||||
"def test_circle_contains_edge():\n",
|
||||
" assert circle_contains(1, origin, Point(1, 0)) # on the circle\n",
|
||||
"\n",
|
||||
"def test_circle_contains_outside():\n",
|
||||
" assert not circle_contains(1, origin, Point(1.1, 0))\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Now running `pytest` would run the test function and report the results.\n",
|
||||
"\n",
|
||||
"## `assert`\n",
|
||||
"\n",
|
||||
"The `assert` statement is used to check that a condition is true.\n",
|
||||
"\n",
|
||||
"If the condition is `True`, nothing happens. If the condition is `False`, an `AssertionError` is raised.\n",
|
||||
"\n",
|
||||
"You can also provide a message to be printed if the assertion fails:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"assert 1 == 2, \"1 is not equal to 2\"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Note:** `assert` is not a function. Using parentheses leads to confusing results because the parentheses are interpreted as a tuple.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"assert(1 == 2, \"1 is not equal to 2\")\n",
|
||||
"\n",
|
||||
"# This is equivalent to:\n",
|
||||
"assert (1 == 2, \"1 is not equal to 2\")\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### Aside: Truthiness\n",
|
||||
"\n",
|
||||
"In Python, every type has an implicit conversion to a boolean value. This is called \"truthiness\".\n",
|
||||
"\n",
|
||||
"The following values are considered \"falsey\":\n",
|
||||
"\n",
|
||||
"* `False`\n",
|
||||
"* `None`\n",
|
||||
"* `0` # int\n",
|
||||
"* `0.0` # float\n",
|
||||
"* `0j` # complex\n",
|
||||
"* \"\" # empty string\n",
|
||||
"* [] # empty list\n",
|
||||
"* () # empty tuple\n",
|
||||
"* {} # empty dict\n",
|
||||
"* set() # empty set\n",
|
||||
"\n",
|
||||
"All other values are considered `True`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"False is False\n",
|
||||
"None is False\n",
|
||||
"0 is False\n",
|
||||
"0.0 is False\n",
|
||||
"0j is False\n",
|
||||
" is False\n",
|
||||
"[] is False\n",
|
||||
"() is False\n",
|
||||
"{} is False\n",
|
||||
"set() is False\n",
|
||||
"True is True\n",
|
||||
"42 is True\n",
|
||||
"3.14 is True\n",
|
||||
"hello is True\n",
|
||||
"[1, 2, 3] is True\n",
|
||||
"{'a': 1} is True\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"values = [False, None, 0, 0.0, 0j, \"\", [], (), {}, set()]\n",
|
||||
"values += [True, 42, 3.14, \"hello\", [1, 2, 3], {\"a\": 1}]\n",
|
||||
"for value in values:\n",
|
||||
" # notice we're using the value as a boolean expression here\n",
|
||||
" if value:\n",
|
||||
" print(f\"{value} is True\")\n",
|
||||
" else:\n",
|
||||
" print(f\"{value} is False\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Writing good tests\n",
|
||||
"\n",
|
||||
"Above we had the tests\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"def test_circle_contains():\n",
|
||||
" # centered at origin, radius 1\n",
|
||||
" assert circle_contains(1, origin, origin)\n",
|
||||
" assert circle_contains(1, origin, Point(.5, .5))\n",
|
||||
"\n",
|
||||
"def test_circle_contains_edge():\n",
|
||||
" assert circle_contains(1, origin, Point(1, 0)) # on the circle\n",
|
||||
"\n",
|
||||
"def test_circle_contains_outside():\n",
|
||||
" assert not circle_contains(1, origin, Point(1.1, 0))\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Why not just do this?\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"\n",
|
||||
"def test_circle_contains():\n",
|
||||
" # centered at origin, radius 1\n",
|
||||
" assert circle_contains(1, origin, origin)\n",
|
||||
" assert circle_contains(1, origin, Point(.5, .5))\n",
|
||||
" assert circle_contains(1, origin, Point(1, 0)) # on the circle\n",
|
||||
" assert not circle_contains(1, origin, Point(1.1, 0))\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"If the first assertion fails, the second assertion will not be run. This makes it harder to debug the problem.\n",
|
||||
"\n",
|
||||
"As you've no doubt noticed throughout these courses, granular tests make debugging easier. It is also easier to reason about what isn't yet being tested.\n",
|
||||
"\n",
|
||||
"**What bugs could be lurking in the code above?**\n",
|
||||
"\n",
|
||||
"### General Rules\n",
|
||||
"\n",
|
||||
"* Each test should test one thing.\n",
|
||||
"* Each test should be independent of the others.\n",
|
||||
"* Each test should be repeatable.\n",
|
||||
"* Each test should be easy to understand.\n",
|
||||
"\n",
|
||||
"### What Tests To Write\n",
|
||||
"\n",
|
||||
"When considering what to test, usually there are a couple of obvious cases. For a string distance function, you might consider you need to have at least one test for when the strings are identical, and one test for when the strings are completely different.\n",
|
||||
"\n",
|
||||
"Those are the obvious cases, it is then worth considering edge cases. What about an empty string? Perhaps a string with one character as well?\n",
|
||||
"\n",
|
||||
"**(0, 1, Many)** is a good rule to consider.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Test One Thing\n",
|
||||
"\n",
|
||||
"If you were testing a function that summed a list of numbers, consider these two approaches:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"def test_sum():\n",
|
||||
" assert sum([]) == 0\n",
|
||||
" assert sum([1]) == 1\n",
|
||||
" assert sum([1, 2, 3]) == 6\n",
|
||||
" with pytest.raises(TypeError):\n",
|
||||
" sum([1, \"hello\"])\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"def test_sum_empty():\n",
|
||||
" assert sum([]) == 0\n",
|
||||
"\n",
|
||||
"def test_sum_one():\n",
|
||||
" assert sum([1]) == 1\n",
|
||||
"\n",
|
||||
"def test_sum_many():\n",
|
||||
" assert sum([1, 2, 3]) == 6\n",
|
||||
"\n",
|
||||
"def test_sum_type_error():\n",
|
||||
" ...\n",
|
||||
" with pytest.raises(TypeError):\n",
|
||||
" sum([1, \"hello\"])\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"By having each test focus on one thing, test failures will be more informative.\n",
|
||||
"\n",
|
||||
"### Test Independence\n",
|
||||
"\n",
|
||||
"Tests should be independent of each other. This means that if one test fails, it should not affect the outcome of any other test.\n",
|
||||
"\n",
|
||||
"This can be a challenge when testing functions that modify data or global state.\n",
|
||||
"\n",
|
||||
"For example:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"def test_create_user():\n",
|
||||
" db = Database(\"test.db\")\n",
|
||||
" db.create_user(username=\"alice\")\n",
|
||||
" assert db.get_user(username=\"alice\").id == 1\n",
|
||||
"\n",
|
||||
"def test_delete_user():\n",
|
||||
" db = Database(\"test.db\")\n",
|
||||
" db.delete_user(username=\"alice\")\n",
|
||||
" assert db.get_user(username=\"alice\") is None\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"These tests are not independent. If the first test fails, the second test will fail because the database will be empty.\n",
|
||||
"\n",
|
||||
"You'd instead likely need to do something like this:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"def create_test_database():\n",
|
||||
" remove_file_if_exists(\"test.db\")\n",
|
||||
" db = Database(\"test.db\")\n",
|
||||
" db.init_schema()\n",
|
||||
" return db\n",
|
||||
"\n",
|
||||
"def test_create_user():\n",
|
||||
" db = create_test_database()\n",
|
||||
" db.create_user(username=\"alice\")\n",
|
||||
" assert db.get_user(username=\"alice\").id == 1\n",
|
||||
"\n",
|
||||
"def test_delete_user():\n",
|
||||
" db = create_test_database()\n",
|
||||
" db.create_user(username=\"alice\")\n",
|
||||
" db.delete_user(username=\"alice\")\n",
|
||||
" assert db.get_user(username=\"alice\") is None\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Note: `test_delete_user` will fail if `create_user` doesn't work. There's still a dependency in terms of behavior in this case, but you can see that the tests can now be run independently of one another since each starts with a blank database.\n",
|
||||
"\n",
|
||||
"#### `pytest` Fixtures\n",
|
||||
"\n",
|
||||
"Another way to handle this is to use `pytest` fixtures. A fixture is a function that is run before each test. It can be used to set up the test environment.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import pytest\n",
|
||||
"\n",
|
||||
"@pytest.fixture\n",
|
||||
"def db():\n",
|
||||
" remove_file_if_exists(\"test.db\")\n",
|
||||
" db = Database(\"test.db\")\n",
|
||||
" db.init_schema()\n",
|
||||
" return db\n",
|
||||
"\n",
|
||||
"# parameter names must match fixture names\n",
|
||||
"def test_create_user(db):\n",
|
||||
" db.create_user(username=\"alice\")\n",
|
||||
" assert db.get_user(username=\"alice\").id == 1\n",
|
||||
"\n",
|
||||
"def test_delete_user(db):\n",
|
||||
" db.create_user(username=\"alice\")\n",
|
||||
" db.delete_user(username=\"alice\")\n",
|
||||
" assert db.get_user(username=\"alice\") is None\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"This is a powerful feature that can be used to set up complex test environments.\n",
|
||||
"\n",
|
||||
"### Test Repeatability\n",
|
||||
"\n",
|
||||
"Tests should be repeatable. This means that if a test fails, it should be possible to run it again and get the same result.\n",
|
||||
"\n",
|
||||
"This means that tests should not depend on external factors such as:\n",
|
||||
"\n",
|
||||
"* The current time or date\n",
|
||||
"* Random numbers\n",
|
||||
"* The state of the network\n",
|
||||
"* The state of the database\n",
|
||||
"\n",
|
||||
"To reduce the chance of a test failing due to an external factor, you can use a library like `freezegun` to freeze the current time that a test sees. The `mock` module can be used to mock out external functions so they return consistent data for the purpose of the test.\n",
|
||||
"\n",
|
||||
"`freezegun`: <https://github.com/spulec/freezegun>\n",
|
||||
"\n",
|
||||
"`mock`: <https://docs.python.org/3/library/unittest.mock.html>\n",
|
||||
"\n",
|
||||
"### Test Readability\n",
|
||||
"\n",
|
||||
"Tests should be easy to understand. This means that the test should be written in a way that makes it clear what is being tested and what the expected result is.\n",
|
||||
"\n",
|
||||
"Make liberal use of comments and descriptive test names to make it clear what is being tested so that when a modification to the code in the future breaks a test, it is easy to understand why.\n",
|
||||
"\n",
|
||||
"## Test Driven Devleopment\n",
|
||||
"\n",
|
||||
"Test Driven Development (TDD) is a software development process that involves writing tests before writing the code that will be tested.\n",
|
||||
"\n",
|
||||
"In many ways this is how your PAs have been structured. By knowing what the expected output is, you can write tests that will fail if the code is not working correctly.\n",
|
||||
"\n",
|
||||
"It can be useful to write tests before writing the code that will be tested. This can help you think through the problem and make sure you understand what the code is supposed to do.\n",
|
||||
"\n",
|
||||
"## Unit Testing vs. Integration Testing\n",
|
||||
"\n",
|
||||
"Unit tests are tests that test individual units of code. These are usually functions or methods.\n",
|
||||
"\n",
|
||||
"Integration tests are tests that test how different units of code work together. It can be useful to have a mixture of both, but unit tests are usually easier to write and maintain.\n",
|
||||
"\n",
|
||||
"In our initial example, we broke `advance_all_students_with_passing_grade` into smaller functions. It may still make sense in some cases to test the integration of these functions to make sure that (e.g.) the list of users being returned is still in the same format expected by the `advance_student` function.\n",
|
||||
"\n",
|
||||
"## `pytest` Features\n",
|
||||
"\n",
|
||||
"### `pytest.fixture`\n",
|
||||
"\n",
|
||||
"As shown above, `pytest` fixtures can be used to set up the test environment or provide data to tests.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import pytest\n",
|
||||
"\n",
|
||||
"@pytest.fixture\n",
|
||||
"def user_list()\n",
|
||||
" return [\n",
|
||||
" {\"name\": \"alice\", \"id\": 1, \"email\": \"alice@domain\"},\n",
|
||||
" {\"name\": \"carol\", \"id\": 3, \"email\": \"carol@domain\"},\n",
|
||||
" {\"name\": \"bob\", \"id\": 2, \"email\": \"bob@domain\"},\n",
|
||||
" {\"name\": \"diego\", \"id\": 4, \"email\": \"diego@otherdomain\"},\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
"def test_sort_users(user_list):\n",
|
||||
" sorted_list = sort_users(user_list)\n",
|
||||
" assert sorted_list == [\n",
|
||||
" {\"name\": \"alice\", \"id\": 1, \"email\": \"alice@domain\"},\n",
|
||||
" {\"name\": \"bob\", \"id\": 2, \"email\": \"bob@domain\"},\n",
|
||||
" {\"name\": \"carol\", \"id\": 3, \"email\": \"carol@domain\"},\n",
|
||||
" {\"name\": \"diego\", \"id\": 4, \"email\": \"diego@otherdomain\"},\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
"def test_filter_users(user_list):\n",
|
||||
" filtered_list = filter_users(user_list, domain=\"domain\")\n",
|
||||
" assert filtered_list == [\n",
|
||||
" {\"name\": \"alice\", \"id\": 1, \"email\": \"alice@domain\"},\n",
|
||||
" {\"name\": \"bob\", \"id\": 2, \"email\": \"bob@domain\"},\n",
|
||||
" {\"name\": \"carol\", \"id\": 3, \"email\": \"carol@domain\"},\n",
|
||||
" ]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### `pytest.raises`\n",
|
||||
"\n",
|
||||
"It's often desirable to test that certain errors were raised. `pytest.raises` can be used to test that a function raises an exception.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"def test_reject_invalid_domain():\n",
|
||||
" with pytest.raises(ValueError):\n",
|
||||
" validate_email(\"alice@invalid$\")\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### Parameterized Tests\n",
|
||||
"\n",
|
||||
"Sometimes the same test needs to be run with different inputs. `pytest` provides a way to do this with parameterized tests.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"@pytest.mark.parametrize(\"str1,str2,expected\", [\n",
|
||||
" (\"abc\", \"abd\", 1),\n",
|
||||
" (\"abc\", \"abc\", 0),\n",
|
||||
" (\"abc\", \"xyz\", 3),\n",
|
||||
" (\"abc\", \"abcd\", 1),\n",
|
||||
"])\n",
|
||||
"def test_hamming_distance(str1, str2, expected):\n",
|
||||
" assert hamming_distance(str1, str2) == expected\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"This runs as three distinct tests in `pytest`, converting each input to a distinct test by calling the test function with the parameters."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"test_hamming_distance[abc-abd-1]\n",
|
||||
"test_hamming_distance[abc-abc-0]\n",
|
||||
"test_hamming_distance[abc-xyz-3]"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
1014
19.scientific-python.ipynb
Normal file
1014
19.scientific-python.ipynb
Normal file
File diff suppressed because one or more lines are too long
401
hashtables.ipynb
Normal file
401
hashtables.ipynb
Normal file
@ -0,0 +1,401 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a6c3f443-273b-4f49-9339-902e3251e0e4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Hash Tables\n",
|
||||
"\n",
|
||||
"A hash table is a collection that maps keys to values. Python's `dict` is an implementation of a hash table.\n",
|
||||
"\n",
|
||||
"For the course project, you will be implementing a hash table without using `dict`.\n",
|
||||
"\n",
|
||||
"### Hash Table Performance\n",
|
||||
"\n",
|
||||
"| Operation | Average | Worst Case | \n",
|
||||
"| --------- | ---- | ---------- |\n",
|
||||
"| lookup | O(1) | O(n) |\n",
|
||||
"| insert | O(1) | O(n) |\n",
|
||||
"| delete | O(1) | O(n) |\n",
|
||||
"\n",
|
||||
"Note: These are average case, as we'll see, depending on implementation, worst case can be much worse.\n",
|
||||
"\n",
|
||||
"A key property for hash tables is that we **do not need to linearly search through them for our data**.\n",
|
||||
"\n",
|
||||
"If you find yourself scanning every element in a hash table, you're doing something wrong.\n",
|
||||
"\n",
|
||||
"### Example\n",
|
||||
"\n",
|
||||
"Let's first model a simple hashtable with fixed capacity of 10. For simplicity we'll stick to string keys.\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"When we get a key-value pair, we need to assign it a bucket.\n",
|
||||
"\n",
|
||||
"How can we write a function that takes a string and assigns it to a bucket?\n",
|
||||
"\n",
|
||||
"1. Turn string into a number. **Hash Function**\n",
|
||||
"2. Take (number % capacity)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "450367cc-fbd5-4b97-89d6-37f69cba5d91",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def strhash(key):\n",
|
||||
" # ord converts a character to it's numeric representation\n",
|
||||
" # ord(\"A\") == 65\n",
|
||||
" # ord(\"z\") == 122\n",
|
||||
" # etc.\n",
|
||||
" return sum(ord(letter) for letter in key)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "e689c2aa-a3a5-4400-b7bb-557944a725da",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"410"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"strhash(\"bear\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "bb545dc8-7db6-46a0-bbc3-716f6bf3639b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"333"
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"strhash(\"fox\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "0ef489a6-7f2c-46aa-aa2e-3ff10241eb46",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Hashtable:\n",
|
||||
" def __init__(self, capacity=10):\n",
|
||||
" self._table = [None] * capacity\n",
|
||||
" self.capacity = capacity\n",
|
||||
"\n",
|
||||
" def __setitem__(self, key, value):\n",
|
||||
" index = strhash(key) % self.capacity\n",
|
||||
" self._table[index] = value\n",
|
||||
"\n",
|
||||
" def __getitem__(self, key):\n",
|
||||
" index = strhash(key) % self.capacity\n",
|
||||
" value = self._table[index]\n",
|
||||
" if value:\n",
|
||||
" return value\n",
|
||||
" else:\n",
|
||||
" raise KeyError(key)\n",
|
||||
"\n",
|
||||
" def display(self):\n",
|
||||
" print(f\"Capacity = {self.capacity}\")\n",
|
||||
" for idx, elem in enumerate(self._table):\n",
|
||||
" if elem:\n",
|
||||
" print(f\"{idx}: {elem}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "8f73d5b3-1fbe-4439-a19f-3c1c73cf1e04",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Capacity = 10\n",
|
||||
"0: 3\n",
|
||||
"3: 12\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"h = Hashtable()\n",
|
||||
"h[\"bear\"] = 3\n",
|
||||
"h[\"fox\"] = 12\n",
|
||||
"h.display()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "1e68e2ee-9feb-4623-88a3-03b16d7fedd4",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"3\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(h[\"bear\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "1535a473-c2e5-474f-8a80-e89ff3bd00bd",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"strhash(\"bear\") == strhash(\"been\") # different word, same hash!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "3458faf2-cc40-4e31-a792-7a1515f718e7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Capacity = 10\n",
|
||||
"0: 12\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"h = Hashtable()\n",
|
||||
"h[\"bear\"] = 33\n",
|
||||
"h[\"been\"] = 12\n",
|
||||
"h.display()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b23a0b1f-1e59-4d83-aa4c-2c57d5706298",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Linear Probing\n",
|
||||
"\n",
|
||||
"One solution is to just walk forward in the storage list, until we find an empty space.\n",
|
||||
"\n",
|
||||
"Either way, we'll need to start storing the key as well. Let's revise our class:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "6a5dd148-07ce-4e02-998a-75b9edce31f7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Hashtable:\n",
|
||||
" def __init__(self, capacity=100):\n",
|
||||
" self._table = [None] * 100\n",
|
||||
" self.capacity = capacity\n",
|
||||
"\n",
|
||||
" def __setitem__(self, key, value):\n",
|
||||
" index = strhash(key) % self.capacity\n",
|
||||
" while self._table[index] is not None:\n",
|
||||
" index += 1\n",
|
||||
" # Handling wrap-around omitted for brevity\n",
|
||||
"\n",
|
||||
" # we now store the key and value\n",
|
||||
" self._table[index] = (key, value)\n",
|
||||
"\n",
|
||||
" def __getitem__(self, key):\n",
|
||||
" index = strhash(key) % self.capacity\n",
|
||||
"\n",
|
||||
" # walk forward until we either reach the item or an empty space\n",
|
||||
" while self._table[index] is not None:\n",
|
||||
" if self._table[index][0] == key:\n",
|
||||
" return self._table[index][1]\n",
|
||||
" index += 1\n",
|
||||
" # Handling wrap-around omitted for brevity\n",
|
||||
"\n",
|
||||
" # if code got here, the item wasn't in the list\n",
|
||||
" raise KeyError(key)\n",
|
||||
"\n",
|
||||
" def display(self):\n",
|
||||
" print(f\"Capacity = {self.capacity}\")\n",
|
||||
" for idx, elem in enumerate(self._table):\n",
|
||||
" if elem:\n",
|
||||
" print(f\"{idx}: {elem}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"id": "3251b310-dfae-4aae-9d04-603a5e20dbea",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Capacity = 10\n",
|
||||
"0: 12\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"h = Hashtable()\n",
|
||||
"h[\"bear\"] = 33\n",
|
||||
"h[\"been\"] = 12\n",
|
||||
"h.display()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"id": "781024b5-a81d-46be-8c87-84f3860395c6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"12\n",
|
||||
"12\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(h[\"bear\"])\n",
|
||||
"print(h[\"been\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f90d7b38-2f69-465d-8da1-59f8efd82909",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Separate Chaining\n",
|
||||
"\n",
|
||||
"Another solution is to use a linked list to store multiple items in the same bucket. One could imagine each bucket being the head of a linked list where items that hash to that value are stored linearly.\n",
|
||||
"\n",
|
||||
"This is the approach we're asking you to use for the course project.\n",
|
||||
"\n",
|
||||
"**What happens if we have a lot of items in the same bucket?**\n",
|
||||
"\n",
|
||||
"### Better Hash Function\n",
|
||||
"\n",
|
||||
"Ideally a hash function will evenly distribute values across the collection.\n",
|
||||
"\n",
|
||||
"A common pattern is to use a polynomial hash function.\n",
|
||||
"\n",
|
||||
"$$h(x_0, ..., x_n) = (\\sum_{i=0}^{k-1}{c_ip^i})\\mod{m}$$\n",
|
||||
"\n",
|
||||
"Where:\n",
|
||||
"- $x_0...x_i $ is the sequence\n",
|
||||
"- $k = len(x)$\n",
|
||||
"- $c_i$ is the numeric value of the character $x_i$ ($ord(x$ in Python)\n",
|
||||
"- $p$ is an arbitrary constant.\n",
|
||||
"- and $m$ is the size of the collection.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
" def _hash(self, key):\n",
|
||||
" \"\"\"\n",
|
||||
" This method takes in a string and returns \n",
|
||||
" an integer value between 0 and self.capacity.\n",
|
||||
"\n",
|
||||
" This particular hash function uses \n",
|
||||
" Horner's rule to compute a large polynomial.\n",
|
||||
" \"\"\"\n",
|
||||
" val = 0\n",
|
||||
" for letter in key:\n",
|
||||
" val = self.P_CONSTANT * val + ord(letter)\n",
|
||||
" return val % self.capacity\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### Questions\n",
|
||||
"\n",
|
||||
"* Linear probing vs. separate chaining? Other approaches?\n",
|
||||
"* What if our hash function wasn't reliable?\n",
|
||||
"\n",
|
||||
"### Rehashing\n",
|
||||
"\n",
|
||||
"As we add more items to our hash table, we'll eventually run out of space. We can increase the capacity of our table, but we'll need to rehash all of our existing items.\n",
|
||||
"\n",
|
||||
"Because which bucket we choose depends on `hash(item) % capacity` items would end up in different buckets if we change capacity.\n",
|
||||
"\n",
|
||||
"This means when we resize, we need to rehash all of our items.\n",
|
||||
"\n",
|
||||
"A common pattern is to double capacity when the table is ~50% full."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c1d5023d-25db-4885-a303-2c34d1a453de",
|
||||
"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.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
542
legislators.csv
Normal file
542
legislators.csv
Normal file
@ -0,0 +1,542 @@
|
||||
person_id,name,current_party
|
||||
ocd-person/cf441c62-91b4-52f5-b9c7-04a45290e5e4,A. Drew Ferguson IV,Republican
|
||||
ocd-person/a5212de0-6253-5b67-8473-2b00d1f22da6,Aaron Bean,Republican
|
||||
ocd-person/d1b6eea9-e526-593d-b87a-0e926c3f2303,Abigail Davis Spanberger,Democratic
|
||||
ocd-person/c5a3238c-f36a-5b17-af62-ca6dcce0b91d,Adam B. Schiff,Democratic
|
||||
ocd-person/55a28978-7661-5a33-a2be-a505a07e2a8e,Adam Smith,Democratic
|
||||
ocd-person/39f36070-b860-5345-a3cc-ea7fdbf7dfb3,Adrian Smith,Republican
|
||||
ocd-person/0d73f18d-36c1-526d-9d5c-5a0a63ff60af,Adriano Espaillat,Democratic
|
||||
ocd-person/2ad84a53-f957-5a9c-861b-413aac608201,Al Green,Democratic
|
||||
ocd-person/fadd82ac-5031-5efd-ae39-1afc3f3cd6fb,Alex Padilla,Democratic
|
||||
ocd-person/1b959af6-5bbc-5e3b-855f-9a140244c31c,Alexander X. Mooney,Republican
|
||||
ocd-person/d2a8d710-a781-5a40-b6f2-e46bffcf40d2,Alexandria Ocasio-Cortez,Democratic
|
||||
ocd-person/76bfaf2b-8259-5f56-bce9-d1c8cd6c780d,Alma S. Adams,Democratic
|
||||
ocd-person/79c4f42e-4775-5ed0-a7e1-d0c942ce6c34,Ami Bera,Democratic
|
||||
ocd-person/2722e0b1-650d-5f77-a348-f7f0d66aa3e2,Amy Klobuchar,Democratic
|
||||
ocd-person/ef4b4ed3-1808-548d-8625-2cea913c2e4a,André Carson,Democratic
|
||||
ocd-person/54f931b7-9a94-5c93-8585-0967370ffb86,Andrea Salinas,Democratic
|
||||
ocd-person/5916e23e-c486-5d60-88c8-56bb65c23763,Andrew Ogles,Republican
|
||||
ocd-person/4ec1dbc4-ea21-5f61-92b1-fa55b47a4c61,Andrew R. Garbarino,Republican
|
||||
ocd-person/0dbe5471-29ea-5c84-8270-f55fee08d118,Andrew S. Clyde,Republican
|
||||
ocd-person/fe2fa2c7-83de-5bf2-b602-6ca9f7fc8a6f,Andy Barr,Republican
|
||||
ocd-person/86b4b077-b73b-579b-bb73-bc5a4a73719a,Andy Biggs,Republican
|
||||
ocd-person/74a68d2f-f563-50d8-80a7-408346b8ba14,Andy Harris,Republican
|
||||
ocd-person/62227c11-1ad4-5395-b233-f1f526efc5b4,Andy Kim,Democratic
|
||||
ocd-person/6b47c0e2-77d5-5126-b7a5-82bea8fb9c67,Angie Craig,Democratic
|
||||
ocd-person/273dd641-da15-5fc0-bdc9-496cc9b65fbd,"Angus S. King, Jr.",Independent
|
||||
ocd-person/7ed34023-b42f-57bc-af69-b36a680122f2,Ann M. Kuster,Democratic
|
||||
ocd-person/12958b9f-2301-5bdb-bf13-81b3de147574,Ann Wagner,Republican
|
||||
ocd-person/047b7a92-9713-54e5-8429-bcd2214908c7,Anna G. Eshoo,Democratic
|
||||
ocd-person/d18ec0cb-328b-54c8-8785-5f924799f5fe,Anna Paulina Luna,Republican
|
||||
ocd-person/e024e123-9750-5f4e-bc3d-6d892218868d,Anthony D’Esposito,Republican
|
||||
ocd-person/50705d33-6967-5424-8f57-7df22ecbc6e6,Ashley Hinson,Republican
|
||||
ocd-person/2519c079-f97e-532b-b53e-167398fd7398,August Pfluger,Republican
|
||||
ocd-person/eb3fa86b-690c-5cc0-8f5e-54af60f28a06,Aumua Amata Coleman Radewagen,Republican
|
||||
ocd-person/20c33933-79f5-58d1-834c-60779932257e,Austin Scott,Republican
|
||||
ocd-person/ab80da0d-902f-5d28-b765-1885853182bd,Ayanna Pressley,Democratic
|
||||
ocd-person/3cbc3ca2-4447-50e2-abed-ba3fe86569d8,Barbara Lee,Democratic
|
||||
ocd-person/13e07344-3cec-5f29-a27b-2dd6979dbeb5,Barry Loudermilk,Republican
|
||||
ocd-person/b242258c-669a-53a7-be30-5f529f03398e,Barry Moore,Republican
|
||||
ocd-person/510c6c69-df0f-5b09-b4c7-066256ace832,Becca Balint,Democratic
|
||||
ocd-person/bb0d60f6-19a4-5229-a67d-a1d428e7c0b2,Ben Cline,Republican
|
||||
ocd-person/5f5817b7-43b0-5bb3-93de-0f838a801635,Ben Ray Luján,Democratic
|
||||
ocd-person/18b53a95-c658-5a23-8c3e-074a7e0d27e3,Benjamin L. Cardin,Democratic
|
||||
ocd-person/c171d352-db84-5c96-8260-1fcd7eab2575,Bennie G. Thompson,Democratic
|
||||
ocd-person/a1ec37b6-9f54-529a-8165-ff96e9d8d93e,Bernard Sanders,Independent
|
||||
ocd-person/861bd195-d8aa-5e72-9699-4f5ad3d5e499,Beth Van Duyne,Republican
|
||||
ocd-person/61c4224a-c1d6-5739-bca6-0db7e58d84bd,Betty McCollum,Democratic
|
||||
ocd-person/851546e4-4af0-5505-8a1c-4f2a83813589,Bill Cassidy,Republican
|
||||
ocd-person/a512ad2f-4554-5b04-a00b-1de672f9099a,Bill Foster,Democratic
|
||||
ocd-person/fb408324-49e1-56ad-8425-65c2a1e88103,Bill Hagerty,Republican
|
||||
ocd-person/ce06af2e-4591-560d-8f14-8f1817c9ad1f,Bill Huizenga,Republican
|
||||
ocd-person/bff03292-2b2c-55fc-aa20-83dce2fccd77,"Bill Pascrell, Jr.",Democratic
|
||||
ocd-person/40abdb56-d1b4-54a3-bc53-b586f8c06ac3,Bill Posey,Republican
|
||||
ocd-person/686325e7-8dc3-587d-9ee1-e0ad14202350,Blaine Luetkemeyer,Republican
|
||||
ocd-person/3854aa11-1cec-58f6-8e90-c721a0db3525,Blake D. Moore,Republican
|
||||
ocd-person/e53e5a13-c82a-5208-96d0-f6769c0d8a67,Bob Good,Republican
|
||||
ocd-person/ff55ab02-9d61-544c-8f4d-710a09d8f5db,Bonnie Watson Coleman,Democratic
|
||||
ocd-person/bc26b71a-566f-57fd-9d5b-23bc27e4c4a4,Brad Finstad,Republican
|
||||
ocd-person/717ac307-3248-5726-bdcf-de58d683943f,Brad R. Wenstrup,Republican
|
||||
ocd-person/4015098b-d823-5776-9b47-ceb09bf523a9,Brad Sherman,Democratic
|
||||
ocd-person/a3c68bbd-f241-52c8-a7e9-7f340f316b7a,Bradley Scott Schneider,Democratic
|
||||
ocd-person/4b5ef955-4806-51d0-83f3-177000f67b3c,Brandon Williams,Republican
|
||||
ocd-person/d1509871-89c0-5f39-bc3d-b55e444e3909,Brendan F. Boyle,Democratic
|
||||
ocd-person/a7ba76d3-828f-52bd-9b30-cdbacf0af2b8,Brett Guthrie,Republican
|
||||
ocd-person/e1f14f02-810c-52c5-8ad5-b2744b95a069,Brian Babin,Republican
|
||||
ocd-person/e7b50abf-92e8-56f1-a5f7-7db9a63fb43f,Brian J. Mast,Republican
|
||||
ocd-person/a6a4c673-58ba-587b-b36b-7a559c379f23,Brian K. Fitzpatrick,Republican
|
||||
ocd-person/bd24fe60-5756-5d23-bcbf-4734f366c257,Brian Schatz,Democratic
|
||||
ocd-person/4f00239f-feef-59fa-87de-5a62e277bb5f,Brittany Pettersen,Democratic
|
||||
ocd-person/c46204bc-8484-585e-91de-6053bd3c3cbc,Bruce Westerman,Republican
|
||||
ocd-person/3203c6f1-12ea-59aa-aeb4-9faa94e04f17,Bryan Steil,Republican
|
||||
ocd-person/f5c47b2f-8eb9-51f9-b403-d41b5bdcd229,Burgess Owens,Republican
|
||||
ocd-person/c281df65-bcd6-5f42-860c-874e38bcd03a,Byron Donalds,Republican
|
||||
ocd-person/6badec3f-9e2b-5f2c-8683-dd8a7ae87d9f,C. A. Dutch Ruppersberger,Democratic
|
||||
ocd-person/9db37a87-2ba9-56a0-9b42-89697222e044,Carlos A. Gimenez,Republican
|
||||
ocd-person/1ad151d2-5d26-5421-9b6f-a87d4a05396f,Carol D. Miller,Republican
|
||||
ocd-person/00bdfb60-1b6f-5a4a-9157-b7cafc399c46,Catherine Cortez Masto,Democratic
|
||||
ocd-person/b420935f-8662-5012-ab5a-befcdc9e39f2,Cathy McMorris Rodgers,Republican
|
||||
ocd-person/d242dd37-9f71-5412-9328-798305153967,Celeste Maloy,Republican
|
||||
ocd-person/ced62f94-88a6-5a4b-b470-89cf1ee4bdac,Charles E. Schumer,Democratic
|
||||
ocd-person/640abb7e-8890-59bc-b5cb-b21c88288657,"Charles J. ""Chuck"" Fleischmann",Republican
|
||||
ocd-person/78a440e5-f314-5f5b-930b-48ab822bb39a,Chellie Pingree,Democratic
|
||||
ocd-person/2398f81d-6371-544d-a7ff-24cf993a716b,Chip Roy,Republican
|
||||
ocd-person/22a8725b-acc8-530a-9a57-6b0a7f750fca,Chris Pappas,Democratic
|
||||
ocd-person/6b768c01-2e7d-5316-9ece-d5e215648f85,Chris Van Hollen,Democratic
|
||||
ocd-person/04b67b59-b46f-5db7-96e3-a78591cf0734,Chrissy Houlahan,Democratic
|
||||
ocd-person/792faee4-b972-54ed-b42d-47b41a22ccb3,Christopher A. Coons,Democratic
|
||||
ocd-person/84a22f15-cf83-5f0b-a048-a6fc50aa60fe,Christopher H. Smith,Republican
|
||||
ocd-person/ef439b89-0461-56c7-aec5-93b6369e18a7,Christopher Murphy,Democratic
|
||||
ocd-person/06299567-cfd4-5679-ad04-893e9f980275,Christopher R. Deluzio,Democratic
|
||||
ocd-person/1b8394c7-93d4-5a22-91cf-264782834b9b,Chuck Edwards,Republican
|
||||
ocd-person/259d896b-e9b5-5237-9243-f5597ae0db7c,Chuck Grassley,Republican
|
||||
ocd-person/3827ab20-4901-56bc-a6ea-e7c275da9eb9,Cindy Hyde-Smith,Republican
|
||||
ocd-person/21f20fe0-1075-512d-99a6-cafcebf57d20,Claudia Tenney,Republican
|
||||
ocd-person/ffc5bfa2-67c8-5743-afa6-3250b0752485,Clay Higgins,Republican
|
||||
ocd-person/dd9d3668-b18a-5102-8628-7f2972350402,Cliff Bentz,Republican
|
||||
ocd-person/45574c8a-7f88-525b-b5b8-255a8d69f335,Colin Z. Allred,Democratic
|
||||
ocd-person/adba4aa8-0d6a-5a7f-9a71-d1a9f9c5e1a0,Cori Bush,Democratic
|
||||
ocd-person/d0bb2662-40b6-52d2-94e6-2bf9d588c954,Cory A. Booker,Democratic
|
||||
ocd-person/e9c6e580-58c8-5a0c-a18c-d11c073a9964,Cory Mills,Republican
|
||||
ocd-person/b6ae1e91-803f-5ce8-98fe-86f85c52dd42,Cynthia M. Lummis,Republican
|
||||
ocd-person/e54a4532-aa1e-5e2d-b630-4f35ef10a46f,Dale W. Strong,Republican
|
||||
ocd-person/ff2f62f3-ccac-57d0-bcad-47a3bfeacb79,Dan Bishop,Republican
|
||||
ocd-person/6e2bcde3-a1f5-5296-9f9f-88c71885f3db,Dan Crenshaw,Republican
|
||||
ocd-person/c2de8671-10f6-5eb3-8624-a9fd877464b5,Dan Newhouse,Republican
|
||||
ocd-person/a6b5e853-563f-5b87-a14a-a1427f56b262,Dan Sullivan,Republican
|
||||
ocd-person/df0edff1-f76c-5916-b28e-f70338b23a7a,Daniel Meuser,Republican
|
||||
ocd-person/4c77555b-f35d-53ca-8c7d-7950b90a1b60,Daniel S. Goldman,Democratic
|
||||
ocd-person/ba55e5b8-ac4e-5ea8-b7a8-d180e10a3562,Daniel T. Kildee,Democratic
|
||||
ocd-person/04db1dc5-1903-5913-a439-fed236ff85a3,Daniel Webster,Republican
|
||||
ocd-person/a494987e-6674-5df8-a8b2-de4b5a99de86,Danny K. Davis,Democratic
|
||||
ocd-person/a7bc3999-648e-58ed-b606-f387e825427c,Darin LaHood,Republican
|
||||
ocd-person/15e5e4c2-568f-55b4-9aa2-54797027c984,Darrell Issa,Republican
|
||||
ocd-person/ef44884b-f8bf-542b-b1ae-f36c7cf8e962,Darren Soto,Democratic
|
||||
ocd-person/cf552a34-e9e1-5de9-9270-b5b441dd89fe,David G. Valadao,Republican
|
||||
ocd-person/e23c900b-5d24-55cb-a1d1-73ac69e597ef,David J. Trone,Democratic
|
||||
ocd-person/5beaa710-fc70-563c-9842-f885e13d9aea,David Kustoff,Republican
|
||||
ocd-person/b7ff0450-1acd-5127-b3f5-7246374119a9,David P. Joyce,Republican
|
||||
ocd-person/5e9726e3-2aae-5708-9227-0e95ac43c203,David Rouzer,Republican
|
||||
ocd-person/100d00e0-275c-5bd0-960e-c24c3b50a8e5,David Schweikert,Republican
|
||||
ocd-person/e6650822-1063-5485-b062-d169ea173ec2,David Scott,Democratic
|
||||
ocd-person/501837d6-d9cc-5b1e-a2e3-e53f047192a5,Dean Phillips,Democratic
|
||||
ocd-person/1e87267c-1e9f-5e46-a266-b1d557a8571b,Deb Fischer,Republican
|
||||
ocd-person/b48d0289-7d22-5bb4-bd17-b351aa3ec4a2,Debbie Dingell,Democratic
|
||||
ocd-person/ce00d736-9c65-52f1-9cdf-aff115c2b7b4,Debbie Lesko,Republican
|
||||
ocd-person/a18130ac-79f6-54ad-a80d-14b143f0742f,Debbie Stabenow,Democratic
|
||||
ocd-person/7bacff4a-1d4a-5c4f-a59c-311206c181d2,Debbie Wasserman Schultz,Democratic
|
||||
ocd-person/ea21df34-9ef4-5746-b83a-700bdc2d1918,Deborah K. Ross,Democratic
|
||||
ocd-person/34d76857-187b-5f62-a2d1-ddfcd13494cf,Delia C. Ramirez,Democratic
|
||||
ocd-person/0a7f80ad-caf7-5d0b-b50b-441764153649,Derek Kilmer,Democratic
|
||||
ocd-person/b96b406a-d60a-57fe-96d1-c1dd5b189ab1,Derrick Van Orden,Republican
|
||||
ocd-person/241df76f-7089-5821-ab7f-bb54d92ee9d7,Diana DeGette,Democratic
|
||||
ocd-person/b090c59e-4d88-5d35-99ba-ec3798f88978,Diana Harshbarger,Republican
|
||||
ocd-person/51152aac-2c93-5445-99ed-026df5b6ad37,Dina Titus,Democratic
|
||||
ocd-person/d409840c-63c1-53e4-9ff6-e5677cef9fe6,Don Bacon,Republican
|
||||
ocd-person/33867761-33c6-5036-b3da-43fb485b65c9,Donald G. Davis,Democratic
|
||||
ocd-person/fa65b2cc-a6a5-56fa-8c78-5bc2ecdd93e6,"Donald M. Payne, Jr.",Democratic
|
||||
ocd-person/b0e4bf70-7945-5f39-bb1b-f993a59367b4,Donald Norcross,Democratic
|
||||
ocd-person/63d110f3-ccdb-5783-9d6a-4a7103f30c01,"Donald S. Beyer, Jr.",Democratic
|
||||
ocd-person/5262c34c-a015-5290-9ca4-3b6ec86f4b1d,Doris O. Matsui,Democratic
|
||||
ocd-person/4e34a7cb-7c10-5e5d-8086-a33ef00207bd,Doug LaMalfa,Republican
|
||||
ocd-person/c4154717-8bdf-5a5e-ac05-24c35f195a78,Doug Lamborn,Republican
|
||||
ocd-person/1bc146c5-42d6-5bf7-a862-34747a4b8ed7,Dusty Johnson,Republican
|
||||
ocd-person/c9d5abc5-4c4a-5ff5-a132-8885eb020e6e,Dwight Evans,Democratic
|
||||
ocd-person/acd197d4-7996-5b4c-b01d-a61702d99385,Earl Blumenauer,Democratic
|
||||
ocd-person/85e43f57-4901-52fd-9fad-57373277f5e1,"Earl L. ""Buddy"" Carter",Republican
|
||||
ocd-person/20f1a4db-1281-5e3f-9d6d-657a3f178b3f,Ed Case,Democratic
|
||||
ocd-person/bceb5ccd-31b0-5d03-894d-03cf2cbb2771,Edward J. Markey,Democratic
|
||||
ocd-person/709b6b03-c38f-540b-85f2-83c16f62d3bd,Eleanor Holmes Norton,Democratic
|
||||
ocd-person/e59ccc1e-b5f0-5b86-9b5b-a8fbf6038665,Elijah Crane,Republican
|
||||
ocd-person/febd3b9d-501f-5191-aaff-87666a5af603,Elise M. Stefanik,Republican
|
||||
ocd-person/e7ebade8-8c17-50e0-ac00-70e0327b9071,Elissa Slotkin,Democratic
|
||||
ocd-person/3de20aaf-f982-5aa3-8280-c5154be829aa,Elizabeth Warren,Democratic
|
||||
ocd-person/8ea538b9-6af5-5683-8b4b-9061f89691c1,Emanuel Cleaver,Democratic
|
||||
ocd-person/93c5c8f8-8311-547d-9465-9e7fdc557769,Emilia Strong Sykes,Democratic
|
||||
ocd-person/9a89c225-65e9-5680-a780-9802c17cb7c4,"Eric A. ""Rick"" Crawford",Republican
|
||||
ocd-person/6a54b336-ad96-5ceb-a963-50fe0f56c288,Eric Burlison,Republican
|
||||
ocd-person/999df51b-9318-55b9-b0f6-d738ffc1d62d,Eric Schmitt,Republican
|
||||
ocd-person/42d739b0-f570-5d50-b549-eeaa2c7507ee,Eric Sorensen,Democratic
|
||||
ocd-person/032302ae-d513-5e31-bafc-8bc3cbb18d7c,Eric Swalwell,Democratic
|
||||
ocd-person/c5e2bb91-8e10-5b4c-a442-bf5edb05bd45,Erin Houchin,Republican
|
||||
ocd-person/90a2bdbf-1b51-5e72-aef9-5a98c305f31d,Frank D. Lucas,Republican
|
||||
ocd-person/c6c1c65f-7735-5ebb-951c-56d6cacc8ebb,Frank J. Mrvan,Democratic
|
||||
ocd-person/dfcc16d4-7116-5a16-bf7f-81c6f10d8276,"Frank Pallone, Jr.",Democratic
|
||||
ocd-person/bd701bdc-2944-5bb8-b4bf-e2914e6e1241,Frederica S. Wilson,Democratic
|
||||
ocd-person/c0f06e59-7d28-535f-8efe-5f49f273763d,Gabe Amo,Democratic
|
||||
ocd-person/e643b29f-840b-51ac-aba1-62c85eb9e36c,Gabe Vasquez,Democratic
|
||||
ocd-person/6b0fb307-b985-56d0-83d3-c17a01e9b98e,Garret Graves,Republican
|
||||
ocd-person/edbfabfd-d26b-5d22-9a5d-f079181608f8,Gary C. Peters,Democratic
|
||||
ocd-person/1add3f9c-2946-50ed-92e9-fa54a98fe985,Gary J. Palmer,Republican
|
||||
ocd-person/ef3e7d6c-ac3c-58d2-9404-0b164aea0477,George S. Helmy,Democratic
|
||||
ocd-person/716b011f-3673-558d-b35f-d5a454cafa81,Gerald E. Connolly,Democratic
|
||||
ocd-person/57016d46-c931-5a93-aeb5-1ffec71fb87e,Glenn Grothman,Republican
|
||||
ocd-person/3e53830a-108c-5864-92f1-9f9c8f7b1d0f,Glenn Ivey,Democratic
|
||||
ocd-person/2faf9e06-f667-5b60-830f-2161dae9c77a,Glenn Thompson,Republican
|
||||
ocd-person/228dc55f-1b76-5458-b344-4df46c4e632a,Grace F. Napolitano,Democratic
|
||||
ocd-person/ae123357-c70e-5d29-b16f-2d17775ab0f6,Grace Meng,Democratic
|
||||
ocd-person/3b0de391-3f75-564b-9b1c-c793300ff1a9,Greg Casar,Democratic
|
||||
ocd-person/63dfcb23-8196-5bd6-a5cc-b6592d99150e,Greg Landsman,Democratic
|
||||
ocd-person/b513aafd-8615-53db-910f-b0d3e4c0dec6,Greg Lopez,Republican
|
||||
ocd-person/4c0bab34-0485-54c6-8b00-15042f52fd87,Greg Pence,Republican
|
||||
ocd-person/3300ee9c-6602-5be9-9bb5-2fb7f65a8d5c,Greg Stanton,Democratic
|
||||
ocd-person/3f4f5bab-eae1-594a-a93f-53c463b03d5b,Gregorio Kilili Camacho Sablan,Democratic
|
||||
ocd-person/b66a5d85-c9cd-5689-a482-d175230ab86d,Gregory F. Murphy,Republican
|
||||
ocd-person/372b42da-f525-5938-9a01-e21378fe287c,Gregory W. Meeks,Democratic
|
||||
ocd-person/cd29931a-8dab-5ad7-8d4e-f0066cce7d4c,Gus M. Bilirakis,Republican
|
||||
ocd-person/58bfb394-46c1-51e6-9f85-c3f091ddada7,Guy Reschenthaler,Republican
|
||||
ocd-person/0223a517-1c97-5425-8bca-2120c45ce2e5,Gwen Moore,Democratic
|
||||
ocd-person/562f0794-c1fb-50ee-b69c-3a01b25cfc3a,H. Morgan Griffith,Republican
|
||||
ocd-person/f06d8480-e875-5184-8316-4140a912a03d,Hakeem S. Jeffries,Democratic
|
||||
ocd-person/62d84fce-0ff4-53df-b7a8-4c02d1dc8654,Haley M. Stevens,Democratic
|
||||
ocd-person/8b8caa4b-52c1-54aa-bb51-bd0bccdc69b9,Harold Rogers,Republican
|
||||
ocd-person/17005404-0e78-5bcc-8a71-d67af0e033fd,Harriet M. Hageman,Republican
|
||||
ocd-person/51b7316e-0885-571b-8a2e-daf54dd906bb,"Henry C. ""Hank"" Johnson, Jr.",Democratic
|
||||
ocd-person/f67869ed-f124-54ce-b870-600ae4ff20e8,Henry Cuellar,Democratic
|
||||
ocd-person/55404260-10e4-59e0-b228-2a01a21fb952,Hillary J. Scholten,Democratic
|
||||
ocd-person/dc1ded48-08a5-5981-be73-53bbbe668782,Ilhan Omar,Democratic
|
||||
ocd-person/73ff0305-598d-5558-9b5e-6834be8a503a,J. French Hill,Republican
|
||||
ocd-person/86b65fd7-4549-51fa-80e8-eaf3daf3e60e,J. Luis Correa,Democratic
|
||||
ocd-person/5a8792bc-1520-56aa-ab19-729008cd559b,J.D. Vance,Republican
|
||||
ocd-person/5f3b131a-0f64-5d55-875a-2861e5347727,Jack Bergman,Republican
|
||||
ocd-person/e62576aa-1bf5-5664-ad0f-b1fdbcdead56,Jack Reed,Democratic
|
||||
ocd-person/2f7f8ec5-f652-5c47-8dcb-06d7bc54557c,Jacky Rosen,Democratic
|
||||
ocd-person/1d87ca8c-1a95-531f-bbdd-34e1679d45d2,Jahana Hayes,Democratic
|
||||
ocd-person/a68063b7-2ce8-5638-a836-4fa7b22b3432,Jake Auchincloss,Democratic
|
||||
ocd-person/7add5a36-095e-5209-b94f-71b436555100,Jake Ellzey,Republican
|
||||
ocd-person/b4bfc55d-3cdd-5a6e-accf-912a2b2d28b8,Jake LaTurner,Republican
|
||||
ocd-person/e79a7ea4-9fcd-5c43-99b3-68bee77eb928,Jamaal Bowman,Democratic
|
||||
ocd-person/e1a8d4da-7cbd-571e-817d-774ff06bb342,James A. Himes,Democratic
|
||||
ocd-person/4f6d6ecb-8f69-5f40-9965-ac5fab1e3dba,James C. Moylan,Republican
|
||||
ocd-person/57b0c699-cef2-5740-bd15-4ad2562f8975,James Comer,Republican
|
||||
ocd-person/e24e02a4-f70c-5b9e-84e2-eda2d153f80f,James E. Clyburn,Democratic
|
||||
ocd-person/e8bb2501-1603-543f-9667-9089f781aa97,James E. Risch,Republican
|
||||
ocd-person/62a44404-9be2-5bbc-b672-0ed5f1aba53d,James Lankford,Republican
|
||||
ocd-person/d44223bc-5f00-56aa-be61-28b5a3b4429d,James P. McGovern,Democratic
|
||||
ocd-person/749232ec-b66c-5bd7-b828-10a466b95f0a,James R. Baird,Republican
|
||||
ocd-person/289b4cb5-a838-5b08-8f74-e06d4d251ae7,Jamie Raskin,Democratic
|
||||
ocd-person/c5e8693c-dca3-5ff7-b456-e71d944e4fb0,Janice D. Schakowsky,Democratic
|
||||
ocd-person/3c47a44a-29b8-5aa1-b61a-9e49ea0caf99,Jared F. Golden,Democratic
|
||||
ocd-person/c2b08e7d-2372-5af6-b333-7ea2787cb3ca,Jared Huffman,Democratic
|
||||
ocd-person/356c2159-c402-51d8-b4eb-697aaff46dc2,Jared Moskowitz,Democratic
|
||||
ocd-person/fafd6715-85a1-509b-98d1-6df68904f028,Jasmine Crockett,Democratic
|
||||
ocd-person/fb2f7d0c-f39b-50a6-8bdc-8bdc181683bc,Jason Crow,Democratic
|
||||
ocd-person/559a5a0c-4b35-56f0-aa59-76c98e6cfb45,Jason Smith,Republican
|
||||
ocd-person/d78f994b-01dc-5dfb-a08f-fc2ca2cef7ec,Jay Obernolte,Republican
|
||||
ocd-person/6d497134-2c53-5987-add8-6fffeaa96cda,Jeanne Shaheen,Democratic
|
||||
ocd-person/5c67147e-00d5-5430-b1c1-59a6da4269d6,Jeff Duncan,Republican
|
||||
ocd-person/4f9693d4-e175-536f-bd51-e884f84b9a6d,Jeff Jackson,Democratic
|
||||
ocd-person/96291b83-ea59-594a-97cf-630189e0b8ed,Jeff Merkley,Democratic
|
||||
ocd-person/a7706596-7110-5866-935b-b44668b92af1,Jefferson Van Drew,Republican
|
||||
ocd-person/130d2a3b-6ca1-560e-b0cd-a7c08366cff3,Jennifer Kiggans,Republican
|
||||
ocd-person/6d89e5cc-c605-55ff-ba4d-b3d58d6ac1af,Jennifer L. McClellan,Democratic
|
||||
ocd-person/660e8554-8d00-501a-bd27-e65689d39837,Jennifer Wexton,Democratic
|
||||
ocd-person/3f563cbe-7057-5771-b8d0-6e2e063da96f,Jenniffer González-Colón,Republican
|
||||
ocd-person/d6cd4f62-7c5f-5595-ac5e-4e40741e5f3b,Jerrold Nadler,Democratic
|
||||
ocd-person/6813a4c1-4353-5517-9314-5d36ecebabfd,Jerry L. Carl,Republican
|
||||
ocd-person/00c39487-8eec-5494-af5e-96e9b025a39b,Jerry Moran,Republican
|
||||
ocd-person/f89c416f-c08d-5251-9a31-201a5265e283,"Jesús G. ""Chuy"" García",Democratic
|
||||
ocd-person/8bd432ce-3c98-5811-afd6-65f19c5ab6ba,Jill N. Tokuda,Democratic
|
||||
ocd-person/befb976c-1369-5d86-a53f-4aeebdf486cc,Jim Banks,Republican
|
||||
ocd-person/8d953afe-9b42-5c80-9f43-4ccf8af79513,Jim Costa,Democratic
|
||||
ocd-person/bc5dadc9-a085-507e-82e1-1622d9a1fc90,Jim Jordan,Republican
|
||||
ocd-person/20be777c-8a2b-54c6-9b54-df88ff19b8ae,Jimmy Gomez,Democratic
|
||||
ocd-person/946e688a-6b60-567e-bea7-893eb4364acc,Jimmy Panetta,Democratic
|
||||
ocd-person/d0fe7bc7-b883-5485-814f-f7cee999e409,Joaquin Castro,Democratic
|
||||
ocd-person/4938e6be-7c14-536d-a559-91c74fcc17db,Jodey C. Arrington,Republican
|
||||
ocd-person/b34622c6-66c7-5f9a-822f-55e3f9ac3c73,Joe Courtney,Democratic
|
||||
ocd-person/3da2fb45-0c89-544c-b41d-888d623cf99c,"Joe Manchin, III",Independent
|
||||
ocd-person/04243e35-118c-5541-a21e-763c594a083a,Joe Neguse,Democratic
|
||||
ocd-person/af50abf4-b711-5bbc-a920-465e39c99f42,Joe Wilson,Republican
|
||||
ocd-person/4d2b82fc-189e-5007-980f-64a85612afdb,John B. Larson,Democratic
|
||||
ocd-person/80f88c07-5f6d-5ca3-8121-9202259a50f2,John Barrasso,Republican
|
||||
ocd-person/b352dd8b-dd06-57b0-833a-2b0b3bd33ad6,John Boozman,Republican
|
||||
ocd-person/d274933a-e19d-5d3b-ab91-dc6611aaadd1,John Cornyn,Republican
|
||||
ocd-person/6f500f52-75ce-5cf0-afc6-5be71f0921d2,John Fetterman,Democratic
|
||||
ocd-person/d4381c32-b267-5e35-b118-c0da3a0a80a1,John Garamendi,Democratic
|
||||
ocd-person/5ab7829c-a819-5616-ac0e-a0aaa359f493,John H. Rutherford,Republican
|
||||
ocd-person/18c027d3-52ca-5a48-a4d2-73167e382096,John Hoeven,Republican
|
||||
ocd-person/f32918a9-b738-5f20-8c3e-f95c7fda80cb,John James,Republican
|
||||
ocd-person/50b75c29-4e98-5622-b60f-59485dcc1141,John Joyce,Republican
|
||||
ocd-person/7a996578-ee76-59c8-856c-4f63861a62da,John Kennedy,Republican
|
||||
ocd-person/a1232c4d-25eb-555a-85a3-b2e168a086c1,John P. Sarbanes,Democratic
|
||||
ocd-person/7b014168-dc13-5568-96df-8c7cbb335268,John R. Carter,Republican
|
||||
ocd-person/7cc5139d-8e53-560c-9828-926395e1552d,John R. Curtis,Republican
|
||||
ocd-person/cb38b814-2794-505a-9232-f1bd56ca3ca0,John R. Moolenaar,Republican
|
||||
ocd-person/b8e3fe12-d102-5c54-a4d2-be9d6a3f73f9,John S. Duarte,Republican
|
||||
ocd-person/342214ae-2e66-50a4-9a10-acc467bd5d98,John Thune,Republican
|
||||
ocd-person/e4ea61a6-63ea-53e6-b61e-4c735a0b7818,John W. Hickenlooper,Democratic
|
||||
ocd-person/a30feb1f-c9fe-5612-808e-8fe5a55b76dc,John W. Rose,Republican
|
||||
ocd-person/4e48da38-17ab-5580-bced-2ea00b9b2843,Jon Ossoff,Democratic
|
||||
ocd-person/9f388589-39f3-5470-af3d-d74720d56afc,Jon Tester,Democratic
|
||||
ocd-person/f862c305-dfc3-5525-a488-8b57d58fad50,Jonathan L. Jackson,Democratic
|
||||
ocd-person/86133add-b3ff-52c2-a71e-442b9afeff6b,Joni Ernst,Republican
|
||||
ocd-person/70681900-af7f-5ee5-b826-7ab8c4194a9e,Joseph D. Morelle,Democratic
|
||||
ocd-person/68651247-63fc-5dad-8071-4efef949f7fd,Josh Brecheen,Republican
|
||||
ocd-person/8ce4e2db-be5a-5493-a399-b2e6061301ba,Josh Gottheimer,Democratic
|
||||
ocd-person/3ed77541-5a79-56b1-94d9-79baa74e938b,Josh Harder,Democratic
|
||||
ocd-person/0a7d370e-88bd-5b83-9b93-c8607c036d7a,Josh Hawley,Republican
|
||||
ocd-person/47fb8c8b-1c71-5c66-9781-94be94803332,Joyce Beatty,Democratic
|
||||
ocd-person/435b9cf1-2f02-5ec2-a54e-a42ef044db07,Juan Ciscomani,Republican
|
||||
ocd-person/904bef1f-7ef4-51af-aeef-b0ac8e1fbe06,Juan Vargas,Democratic
|
||||
ocd-person/a06fc4e8-2e1e-52b6-9aef-83d9405fe16b,Judy Chu,Democratic
|
||||
ocd-person/84e51316-26ee-55c7-88e8-ae3bd2b7b3cc,Julia Brownley,Democratic
|
||||
ocd-person/2a914bb0-5ddc-52d0-abb0-f0cd7830fc5f,Julia Letlow,Republican
|
||||
ocd-person/0963048e-e973-5563-a888-497a3bd4a492,Kat Cammack,Republican
|
||||
ocd-person/c882e018-77a3-529f-83ca-151e98d04264,Katherine M. Clark,Democratic
|
||||
ocd-person/4e9be052-7054-5a13-84af-4e5176dbac41,Kathy Castor,Democratic
|
||||
ocd-person/1c6b4ab9-cf1b-5dc1-a537-b991aff8fe5b,Kathy E. Manning,Democratic
|
||||
ocd-person/7bf077d8-e8b9-503e-b9c2-d18b55951e93,Katie Boyd Britt,Republican
|
||||
ocd-person/8582a25f-087e-5d46-8c12-7dd2e5cf5417,Katie Porter,Democratic
|
||||
ocd-person/32f7cd03-4f8d-5354-b6d1-114bdd4f9af1,Kay Granger,Republican
|
||||
ocd-person/404f8ca3-d216-5c95-b5aa-17176b25aa16,Keith Self,Republican
|
||||
ocd-person/ea4b65ca-7dbf-575b-abdb-1ac17d6ebb13,Kelly Armstrong,Republican
|
||||
ocd-person/3ca12a7a-5192-58bf-ba92-c219af17d74c,Ken Calvert,Republican
|
||||
ocd-person/b18c868c-a789-5a02-8070-c0c473d55304,Kevin Cramer,Republican
|
||||
ocd-person/139e15e1-4a50-5126-ad7a-b462c44f00e0,Kevin Hern,Republican
|
||||
ocd-person/4aee9639-900f-5593-aab0-b55bb3e8da51,Kevin Kiley,Republican
|
||||
ocd-person/c0400bec-65fe-5112-bf85-3a185ed0b601,Kevin Mullin,Democratic
|
||||
ocd-person/eb152f16-def8-5b51-9379-e7e463628ad6,Kim Schrier,Democratic
|
||||
ocd-person/d3f90fd1-5f64-5d18-a658-bdd021b89f46,Kirsten E. Gillibrand,Democratic
|
||||
ocd-person/79575558-ef44-5bb5-9c64-3d3fe3fb4427,Kweisi Mfume,Democratic
|
||||
ocd-person/37a72ecf-c1ae-5c91-b4ee-d72f4e9e8894,Kyrsten Sinema,Independent
|
||||
ocd-person/8d52be7e-dba0-5b01-bb9a-c0cfb72fa609,Lance Gooden,Republican
|
||||
ocd-person/0490575c-d32c-56f5-9d82-c0511ebe4fb8,Laphonza R. Butler,Democratic
|
||||
ocd-person/9b31b2fc-8303-5ad0-85d3-1051a49aedb2,Larry Bucshon,Republican
|
||||
ocd-person/96350e36-02c1-512a-8b83-fdd0dd93be88,Laurel M. Lee,Republican
|
||||
ocd-person/bbaa33e5-6ab2-5fba-bb46-35e44f89e553,Lauren Boebert,Republican
|
||||
ocd-person/9415f4f1-c2b8-5543-b695-d8cace3373f2,Lauren Underwood,Democratic
|
||||
ocd-person/b01048a9-27a5-5fed-b5ef-7bf3b3be6d04,Linda T. Sánchez,Democratic
|
||||
ocd-person/111e4df8-6815-5549-9833-57120f302f81,Lindsey Graham,Republican
|
||||
ocd-person/0b32bee9-863e-522f-99b8-9ad8e5d8f42e,Lisa Blunt Rochester,Democratic
|
||||
ocd-person/f8a1c19c-3aa4-5c20-a8a4-211a40b2c540,Lisa C. McClain,Republican
|
||||
ocd-person/cd76253c-a786-586d-aaac-bd14db985c3b,Lisa Murkowski,Republican
|
||||
ocd-person/b2b37c5e-17c0-5833-b5e0-fe4f93834761,Lizzie Fletcher,Democratic
|
||||
ocd-person/09fc76c2-eb6b-52c2-bc3d-de183e362df0,Lloyd Doggett,Democratic
|
||||
ocd-person/0f2326f2-b5dc-5428-bcaa-9a1078d0750c,Lloyd Smucker,Republican
|
||||
ocd-person/6dca533f-6c45-5308-9d6c-b579d4baf301,Lois Frankel,Democratic
|
||||
ocd-person/dba5c00d-d539-5816-8781-e63f28d8b3e2,Lori Chavez-DeRemer,Republican
|
||||
ocd-person/f8d561c8-c0f2-5251-9d52-53289b82c7d9,Lori Trahan,Democratic
|
||||
ocd-person/b5d26a8a-2954-574c-abf8-1c232e928c9c,Lucy McBath,Democratic
|
||||
ocd-person/1daf07ea-2575-511e-a5a8-47f0662cf209,Madeleine Dean,Democratic
|
||||
ocd-person/fe3cbb3c-90cd-5661-8f02-2e7da15459b8,Marc A. Veasey,Democratic
|
||||
ocd-person/014b069e-c444-50fe-99ef-bf72ae5aecd5,Marco Rubio,Republican
|
||||
ocd-person/5cc850f2-c4fa-5844-ab4c-bb44a07159ac,Marcus J. Molinaro,Republican
|
||||
ocd-person/b6f3dafd-0c6e-5694-ac20-59a88e891f62,Marcy Kaptur,Democratic
|
||||
ocd-person/c59c2d02-3a1e-55a7-b1eb-638a902899d5,Margaret Wood Hassan,Democratic
|
||||
ocd-person/46c3b77a-7d00-5ecc-83d0-04c8fa05bf04,Maria Cantwell,Democratic
|
||||
ocd-person/23524e03-1206-50cb-844d-ddea47f258da,Maria Elvira Salazar,Republican
|
||||
ocd-person/fc8623ea-be1e-518f-aa76-3598910fa676,Mariannette Miller-Meeks,Republican
|
||||
ocd-person/3d465b8f-2f67-5283-8cab-da3990ec8c49,Marie Gluesenkamp Perez,Democratic
|
||||
ocd-person/f0914f67-02b0-5f3c-8f03-949f79c30f62,Marilyn Strickland,Democratic
|
||||
ocd-person/7e5729d1-198d-5389-be51-d1e05969729c,Mario Diaz-Balart,Republican
|
||||
ocd-person/8c511e48-a002-5f1c-a4b9-1cd18b7f7a6e,Marjorie Taylor Greene,Republican
|
||||
ocd-person/baf62641-318a-58be-bb76-f7c6aeb97684,Mark Alford,Republican
|
||||
ocd-person/a1d66d4f-5f94-5605-9e25-96c8f5b4e2df,Mark DeSaulnier,Democratic
|
||||
ocd-person/e58ac762-d546-52f3-8efd-8a2c8f12f731,Mark E. Amodei,Republican
|
||||
ocd-person/92fdf72b-20aa-5d08-83b8-833c4714b0ac,Mark E. Green,Republican
|
||||
ocd-person/30665d55-5695-5ede-930d-c92e63e4ee65,Mark Kelly,Democratic
|
||||
ocd-person/50093b91-c03b-5dbf-acb8-e5881dd576e4,Mark Pocan,Democratic
|
||||
ocd-person/0149412b-3e52-5743-bf11-a11ef4a98856,Mark R. Warner,Democratic
|
||||
ocd-person/d01bffb6-a515-5ca5-8203-3a9b8d5da15e,Mark Takano,Democratic
|
||||
ocd-person/c1fcdb86-e58e-59ed-94f2-40e481824423,Markwayne Mullin,Republican
|
||||
ocd-person/fad2ab8c-d191-5eb8-9bd8-5bbc44a35f0d,Marsha Blackburn,Republican
|
||||
ocd-person/fb46b038-d2a8-5824-bb36-deb07f8d9f54,Martin Heinrich,Democratic
|
||||
ocd-person/b98a30a0-ae7f-5910-9883-3132a7164446,Mary E. Miller,Republican
|
||||
ocd-person/4dc45e4a-78e1-545f-94c1-10c1d9a12f15,Mary Gay Scanlon,Democratic
|
||||
ocd-person/be59b2eb-82fa-5b34-af53-30a9aa8b1123,Mary Sattler Peltola,Democratic
|
||||
ocd-person/1f22bb4c-3315-53ae-848a-e30bb8fec18e,Matt Cartwright,Democratic
|
||||
ocd-person/89e031c0-3988-5b08-b7a3-7d4e63eb0579,Matt Gaetz,Republican
|
||||
ocd-person/5b030c5d-0d50-5452-b2f8-95f8659056fb,"Matthew M. Rosendale, Sr.",Republican
|
||||
ocd-person/a26ef77d-1f50-5c77-918d-83f917ac83fb,Max L. Miller,Republican
|
||||
ocd-person/fc7a4a9e-9274-546f-ae5c-bcf46f3fe0f2,Maxine Waters,Democratic
|
||||
ocd-person/f0bef4bc-bb68-55ca-afb8-9104567b2f17,Maxwell Frost,Democratic
|
||||
ocd-person/ee89a520-227a-575d-8379-5d36b6e6b2a2,Mazie K. Hirono,Democratic
|
||||
ocd-person/e3c837d0-9b42-53c9-a131-896bb28aa319,Melanie A. Stansbury,Democratic
|
||||
ocd-person/91ba3b6a-a4c8-54ab-8964-8498641a6d8f,Michael A. Rulli,Republican
|
||||
ocd-person/e40d8398-4cca-57bb-a8cc-8376230801d4,Michael C. Burgess,Republican
|
||||
ocd-person/da5e831e-227c-58a1-bf1a-86782158fb57,Michael Cloud,Republican
|
||||
ocd-person/16a0a125-6ebe-58b3-810f-df10c0e7df1f,Michael F. Bennet,Democratic
|
||||
ocd-person/6b015607-c3dd-5867-a1bb-733bf84fe091,Michael Guest,Republican
|
||||
ocd-person/ba023811-213b-5bb1-a0dc-11a9458364f1,Michael K. Simpson,Republican
|
||||
ocd-person/029be488-4aad-5a5f-95f1-7ab1aaf27c29,Michael Lawler,Republican
|
||||
ocd-person/bac6c65d-846b-5e60-9532-fa216c99ccf6,Michael R. Turner,Republican
|
||||
ocd-person/15d37180-ddd2-5bb6-8dd4-cdd2690eca86,Michael T. McCaul,Republican
|
||||
ocd-person/f335088b-3b7b-5009-9dd9-f389ffe59cdb,Michael Waltz,Republican
|
||||
ocd-person/66724fb4-e553-59cb-b8ba-314e3bf9f1ea,Michelle Fischbach,Republican
|
||||
ocd-person/b95a5cd3-53ca-5f03-8b14-703add32cf84,Michelle Steel,Republican
|
||||
ocd-person/f49d7d57-812e-584d-85f7-0c3b547bfca4,Mike Bost,Republican
|
||||
ocd-person/c3e17251-9796-592a-a8ed-8dea288dadf7,Mike Braun,Republican
|
||||
ocd-person/e2402add-94f2-53fa-9f40-69ba590c744f,Mike Carey,Republican
|
||||
ocd-person/0f7a88d1-4e4c-565a-b905-706181d7b561,Mike Collins,Republican
|
||||
ocd-person/9243a3a9-4e91-5fc8-9643-ae46455b688b,Mike Crapo,Republican
|
||||
ocd-person/fef4e629-aa7e-5bc5-9128-abfce1af96d5,Mike Ezell,Republican
|
||||
ocd-person/51e14e3d-a2c7-5d16-81d5-6608049b5d7e,Mike Flood,Republican
|
||||
ocd-person/0f9b050b-b8cf-56d9-bc31-edfcdd3c2fe5,Mike Gallagher,Republican
|
||||
ocd-person/db31d257-8b81-52c8-a2e1-d26c6ee4a8be,Mike Garcia,Republican
|
||||
ocd-person/ef2a1e73-edb7-5f53-9f61-da2020fc417d,Mike Johnson,Republican
|
||||
ocd-person/72511635-46e3-536d-8880-b32c7cf3e470,Mike Kelly,Republican
|
||||
ocd-person/461257ff-088f-5edd-b342-4652ce1c111f,Mike Lee,Republican
|
||||
ocd-person/ac0c3c4b-14c8-5bc1-bb8b-001af291ee3d,Mike Levin,Democratic
|
||||
ocd-person/b8578429-a84d-5542-a903-02feaee3a7d4,Mike Quigley,Democratic
|
||||
ocd-person/612162b9-752c-50f4-b2e5-de10dae5c160,Mike Rogers,Republican
|
||||
ocd-person/bfd392c5-2d61-56fa-94c6-ea12aaee7ea6,Mike Rounds,Republican
|
||||
ocd-person/237700e9-fd25-5daa-a301-2fde714f5923,Mike Thompson,Democratic
|
||||
ocd-person/bbe70084-5f54-5897-8518-a9467558a4b1,Mikie Sherrill,Democratic
|
||||
ocd-person/200bd7b3-ce8e-5541-a649-b53e30862567,Mitch McConnell,Republican
|
||||
ocd-person/2279327b-86e8-5baf-ad04-7b3e20f3da0c,Mitt Romney,Republican
|
||||
ocd-person/c03dd126-0872-5937-9967-68aedb1ab964,Monica De La Cruz,Republican
|
||||
ocd-person/868d6300-e9e7-5df4-bfe1-2e7fd1a632ac,Morgan Luttrell,Republican
|
||||
ocd-person/d9c43ab0-97c8-565b-80cf-9da35c1ccbee,Morgan McGarvey,Democratic
|
||||
ocd-person/c50627f5-6447-55e3-9ca9-183daf188b58,Nancy Mace,Republican
|
||||
ocd-person/8056c810-7170-5009-88c3-a670ab30164b,Nancy Pelosi,Democratic
|
||||
ocd-person/5ec7a759-2c3a-5270-8328-13c7ac611580,Nanette Diaz Barragán,Democratic
|
||||
ocd-person/0c6bf250-87f0-5c8b-8c0f-31366a703a37,Nathaniel Moran,Republican
|
||||
ocd-person/cebc95c4-7c20-58c5-829c-c3391f0761fa,Neal P. Dunn,Republican
|
||||
ocd-person/a4321566-0258-5d46-bc51-c1f77ba95ba0,Nicholas A. Langworthy,Republican
|
||||
ocd-person/30fe5d74-0224-5d11-92d2-5766471e6cc5,Nick LaLota,Republican
|
||||
ocd-person/d47735a4-c407-5389-bfd2-f638ffccdd06,Nicole Malliotakis,Republican
|
||||
ocd-person/132a1bba-204a-5d4f-a406-40b4342bad1b,Nikema Williams,Democratic
|
||||
ocd-person/f2c67d83-e6fb-5fa9-aa38-663e9f62e81b,Nikki Budzinski,Democratic
|
||||
ocd-person/32caaab6-5712-57c2-83c6-7b226b2c1056,Norma J. Torres,Democratic
|
||||
ocd-person/bc18d350-32b2-5e37-8b43-6f85ae9b5b09,Nydia M. Velázquez,Democratic
|
||||
ocd-person/425d847d-6fbf-55a7-a117-76bca5e3f299,Pat Fallon,Republican
|
||||
ocd-person/10de7024-4b40-57b0-ae78-101372fd4a02,Patrick Ryan,Democratic
|
||||
ocd-person/3ae689a1-81a2-5c40-b26e-ee49648945d6,Patrick T. McHenry,Republican
|
||||
ocd-person/eb3ab543-13a1-53db-a8a1-459e8e91b701,Patty Murray,Democratic
|
||||
ocd-person/5eae38e3-8420-5c09-831a-db73d9cba978,Paul A. Gosar,Republican
|
||||
ocd-person/19360ce3-5ad4-5b67-b253-0239a5360fbb,Paul Tonko,Democratic
|
||||
ocd-person/705749f4-c12c-5090-88fa-012d36611500,Pete Aguilar,Democratic
|
||||
ocd-person/e1b9405a-e695-5bc5-b3b0-6cdc1415f53c,Pete Ricketts,Republican
|
||||
ocd-person/4325bd84-1297-5481-a6b7-80534123c81f,Pete Sessions,Republican
|
||||
ocd-person/54c25fbc-b91d-5d2b-8403-9b8fb1fb6792,Pete Stauber,Republican
|
||||
ocd-person/8addb5a8-a569-54b2-811b-b5d091350411,Peter Welch,Democratic
|
||||
ocd-person/7849cc06-924b-5f36-a446-1f97d9fbdc63,Pramila Jayapal,Democratic
|
||||
ocd-person/b13e8680-abc9-51dc-a6b6-bed78927bfff,Raja Krishnamoorthi,Democratic
|
||||
ocd-person/06cee575-8fbe-5552-9f2b-9fe5aa2a3725,Raúl M. Grijalva,Democratic
|
||||
ocd-person/9b2b75b5-2641-51be-91c3-9d14d40e4d1a,Ralph Norman,Republican
|
||||
ocd-person/7a1c13f9-1aac-5461-aa2a-11642749828d,Rand Paul,Republican
|
||||
ocd-person/31a92a8a-f498-5ca5-a37b-fd92b162c913,Randy Feenstra,Republican
|
||||
ocd-person/4662eadc-a9a7-500c-b9c2-521a013d3729,"Randy K. Weber, Sr.",Republican
|
||||
ocd-person/37f5a4b9-98b2-5c3d-857b-6e02f5123345,Raphael G. Warnock,Democratic
|
||||
ocd-person/e7497932-512f-5b6f-8830-aa4b6737cd2e,Rashida Tlaib,Democratic
|
||||
ocd-person/4db06595-7db2-51a8-8574-703e9af111b9,Raul Ruiz,Democratic
|
||||
ocd-person/62fd9e8b-80ea-5484-b1f1-3f3b4c350cc3,Richard Blumenthal,Democratic
|
||||
ocd-person/882d0f96-61bb-57b0-9683-c72425d337e9,Richard E. Neal,Democratic
|
||||
ocd-person/18943ddd-9052-5b22-905b-65ff2ac3abf7,Richard Hudson,Republican
|
||||
ocd-person/7d0c4665-2bcf-5e53-b450-25461cd13d85,Richard J. Durbin,Democratic
|
||||
ocd-person/3056cc98-9ca1-5293-8064-fc12fd9c689f,Richard McCormick,Republican
|
||||
ocd-person/9f1d5b03-66ab-5d94-9b92-aed4e8168c4d,Rick Larsen,Democratic
|
||||
ocd-person/3a57e816-1e10-58b5-8394-0272542ca567,Rick Scott,Republican
|
||||
ocd-person/4cdf55a7-a62e-5b3d-a07f-305f4e9dc5c1,Rick W. Allen,Republican
|
||||
ocd-person/3a4aef6c-28c5-5cb7-a664-0e8c9d0c4fd2,Ritchie Torres,Democratic
|
||||
ocd-person/1256e24c-ef63-5a90-9cf6-1da0dcd63ce8,Ro Khanna,Democratic
|
||||
ocd-person/1a69c825-1015-5d72-a8d8-a720d586c3b4,Robert B. Aderholt,Republican
|
||||
ocd-person/b20b2d62-fa4a-5014-baac-2f86e1c691eb,"Robert C. ""Bobby"" Scott",Democratic
|
||||
ocd-person/2158a719-5cfa-5c41-92f7-4f0853782d2b,Robert E. Latta,Republican
|
||||
ocd-person/48a4fe68-6141-50ff-8d0b-0693119fd250,Robert Garcia,Democratic
|
||||
ocd-person/0adba0f5-0723-584b-8071-3e442a01f2d2,Robert J. Wittman,Republican
|
||||
ocd-person/a516a327-22fc-57af-931b-f28926b44b85,Robert Menendez,Democratic
|
||||
ocd-person/18aff1ad-b362-53c8-bc7c-59cda8993c62,"Robert P. Casey, Jr.",Democratic
|
||||
ocd-person/ced9bf2d-1308-5316-94c0-c1410716021a,Robin L. Kelly,Democratic
|
||||
ocd-person/8fe2b037-b8ff-5161-9bb4-196e9f1d9dca,Roger F. Wicker,Republican
|
||||
ocd-person/09a67947-f66a-55ac-b4ba-5c656ad7f67d,Roger Marshall,Republican
|
||||
ocd-person/e77e9595-b0fb-5923-a051-9f3221d8d6a9,Roger Williams,Republican
|
||||
ocd-person/09eb0ce6-8616-5896-b1d2-d90f494eb4d9,Ron Estes,Republican
|
||||
ocd-person/67d8f8b5-1fad-5132-9da8-3210783163a8,Ron Johnson,Republican
|
||||
ocd-person/7b0a82d1-eb2f-53a3-8352-de8b64d41060,Ron Wyden,Democratic
|
||||
ocd-person/417128fd-ee37-5676-988d-263b908aa027,Ronny Jackson,Republican
|
||||
ocd-person/30e732cb-6e0a-5920-bd7e-8d62ca9b2f7c,Rosa L. DeLauro,Democratic
|
||||
ocd-person/256da84c-1b8a-5d48-99ba-9c9f7dd2d310,Ruben Gallego,Democratic
|
||||
ocd-person/bf37099b-56fe-54fe-acc1-a6d79a0107d1,Rudy Yakym III,Republican
|
||||
ocd-person/59f2dee7-1c9f-588e-a8ca-158e054f7fca,Russ Fulcher,Republican
|
||||
ocd-person/3036516e-5f78-5d6a-9160-989a3f6cd149,Russell Fry,Republican
|
||||
ocd-person/23aee4a1-f0aa-5803-9678-aebad9194f19,Ryan K. Zinke,Republican
|
||||
ocd-person/a106e70c-7857-5d7c-8252-5f4768818ef2,Salud O. Carbajal,Democratic
|
||||
ocd-person/82ed7662-b9c2-53f7-bab6-c2d59732128b,Sam Graves,Republican
|
||||
ocd-person/bbc6615a-22ca-51f6-b674-8c7753e93333,"Sanford D. Bishop, Jr.",Democratic
|
||||
ocd-person/7c181af1-a048-53f0-a16c-833ffd27aef4,Sara Jacobs,Democratic
|
||||
ocd-person/e34e7060-b2be-56c9-a20f-42de3d875b88,Scott DesJarlais,Republican
|
||||
ocd-person/ad74f627-3223-5505-811c-599046becb2e,Scott Fitzgerald,Republican
|
||||
ocd-person/04fde057-6aef-56ae-9baa-b1450d74ab09,Scott Franklin,Republican
|
||||
ocd-person/379b2f6a-82e3-572b-a471-75020486662e,Scott H. Peters,Democratic
|
||||
ocd-person/2ac15c4d-4052-5a49-9b5c-70b93a4e325e,Scott Perry,Republican
|
||||
ocd-person/89f8b007-1bf3-589a-bffe-92acf526f448,Sean Casten,Democratic
|
||||
ocd-person/2b7e8cfa-f37a-5155-ac79-e769b3cf71da,Seth Magaziner,Democratic
|
||||
ocd-person/7cdb552c-a069-5bae-8c32-c42a2f6c04f6,Seth Moulton,Democratic
|
||||
ocd-person/70056f40-1938-557d-be5d-ddb841c9f19a,Sharice Davids,Democratic
|
||||
ocd-person/89e894b3-e6a6-5c7c-bc77-dd60cc826b0d,Sheila Cherfilus-McCormick,Democratic
|
||||
ocd-person/99710435-8a59-5f14-9acd-da267980551c,Sheila Jackson Lee,Democratic
|
||||
ocd-person/fd0623ac-bbc8-5c5e-839f-37148d89c36e,Sheldon Whitehouse,Democratic
|
||||
ocd-person/793e5b46-2682-51ff-bfca-adf217ca9a65,Shelley Moore Capito,Republican
|
||||
ocd-person/b84b6427-85e2-5d0c-b9e8-a44270378405,Sherrod Brown,Democratic
|
||||
ocd-person/f2916088-1774-50ba-8023-34f7fe686e49,Shontel M. Brown,Democratic
|
||||
ocd-person/cca4b382-1b0b-5872-86a8-abe74e9f6e3a,Shri Thanedar,Democratic
|
||||
ocd-person/8b830e4d-1e2b-5b7b-9f71-6152222a342f,Stacey E. Plaskett,Democratic
|
||||
ocd-person/5554fdf4-9035-5d23-aeb0-fee7d786fa81,Steny H. Hoyer,Democratic
|
||||
ocd-person/2add0122-3206-5502-985b-18808db8f685,Stephanie I. Bice,Republican
|
||||
ocd-person/cc7120d8-f57d-5841-9526-3429e9f0f2c2,Stephen F. Lynch,Democratic
|
||||
ocd-person/e56dabed-c7b4-51c2-a29b-c9850bc9feff,Steve Cohen,Democratic
|
||||
ocd-person/75cfdbf0-b681-5535-8a97-b53310335e72,Steve Daines,Republican
|
||||
ocd-person/b86826b1-800d-5976-98fa-617ccb74ce88,Steve Scalise,Republican
|
||||
ocd-person/b3fc0e27-b0a3-5106-ae4f-65d6cc93c031,Steve Womack,Republican
|
||||
ocd-person/980a78cc-847f-50be-8967-6c8895ad337e,Steven Horsford,Democratic
|
||||
ocd-person/e2bd9b69-7425-5f80-b432-41b690306379,Summer L. Lee,Democratic
|
||||
ocd-person/a6f624bf-9a40-53ad-a0da-92f115d619aa,Susan M. Collins,Republican
|
||||
ocd-person/b5356530-dd09-5b14-98f2-365d70bf4e5c,Susan Wild,Democratic
|
||||
ocd-person/4333db3d-a55e-5d8e-b2ec-1041414ba2e6,Susie Lee,Democratic
|
||||
ocd-person/799d9723-1f90-5558-b8c6-6f293c7eaddd,Suzan K. DelBene,Democratic
|
||||
ocd-person/90d40f72-ffae-544d-86bb-b41605730fee,Suzanne Bonamici,Democratic
|
||||
ocd-person/1608d897-8cf1-5902-9e45-fbd0bbd72cca,Sydney Kamlager-Dove,Democratic
|
||||
ocd-person/168e0e9e-0d4c-57d2-99a6-8fc99be594be,Sylvia R. Garcia,Democratic
|
||||
ocd-person/d7c97bc3-b7cb-585b-b9e3-def97fcb9db6,Tammy Baldwin,Democratic
|
||||
ocd-person/c02182c1-3275-5f3e-9c66-2f0873cc72c7,Tammy Duckworth,Democratic
|
||||
ocd-person/67c3f0bb-7182-51b8-98d0-253144992bfe,Ted Budd,Republican
|
||||
ocd-person/c4d35f64-f25b-5888-9fcb-f3cb97df500e,Ted Cruz,Republican
|
||||
ocd-person/b472f29c-b960-5cea-b5fb-0e9d4d6d10a4,Ted Lieu,Democratic
|
||||
ocd-person/1548bb05-ef78-5582-9058-fd92d3c9c61c,Teresa Leger Fernandez,Democratic
|
||||
ocd-person/f747c3f1-7247-5c91-9870-901ec617e884,Terri A. Sewell,Democratic
|
||||
ocd-person/3ad2df38-e817-50b9-924d-9dbd4bba94a8,Thom Tillis,Republican
|
||||
ocd-person/1cbf8801-61cd-5f46-93c1-0d02f110035a,"Thomas H. Kean, Jr.",Republican
|
||||
ocd-person/7d1234be-d22a-5374-8022-59a795f0f3f4,Thomas Massie,Republican
|
||||
ocd-person/5048bd11-acf0-5775-a75f-5f085fc8bc11,Thomas P. Tiffany,Republican
|
||||
ocd-person/762f36c5-6766-5708-9066-d1d6340500d3,Thomas R. Carper,Democratic
|
||||
ocd-person/4182b897-5c2e-5dff-a87c-aa7911e81a3d,Thomas R. Suozzi,Democratic
|
||||
ocd-person/06b83e26-fe35-526d-86fb-7a6d80b20d1a,Tim Burchett,Republican
|
||||
ocd-person/4d537f5f-04fd-578a-a8d2-61dd4972e758,Tim Kaine,Democratic
|
||||
ocd-person/3bb4a99e-9448-5b35-86cd-114bd035535e,Tim Scott,Republican
|
||||
ocd-person/9e622be4-95d2-5bf7-a99f-543d45400e82,Tim Walberg,Republican
|
||||
ocd-person/7d860788-e85f-5f23-a7dc-133364f9d4e9,Timothy M. Kennedy,Democratic
|
||||
ocd-person/f82067c3-a257-54ae-b6bd-ebe5178372e7,Tina Smith,Democratic
|
||||
ocd-person/7ec39cbb-df0e-5970-aba1-5722964f55bb,Todd Young,Republican
|
||||
ocd-person/34706e89-9ed8-5078-b825-f310caf5a8f6,Tom Cole,Republican
|
||||
ocd-person/a0c9885f-b9f8-5045-9e74-044a886b9a6e,Tom Cotton,Republican
|
||||
ocd-person/08e42c4f-2c5e-5fe0-87cf-0e8de2bdb52d,Tom Emmer,Republican
|
||||
ocd-person/173a4f3f-e38f-569e-97b2-e0424195f16c,Tom McClintock,Republican
|
||||
ocd-person/0ee1b661-2035-5dc1-ab1c-b87d25682775,Tommy Tuberville,Republican
|
||||
ocd-person/147fa8d0-050e-585a-b299-b82e84db0845,Tony Cárdenas,Democratic
|
||||
ocd-person/7e086fc4-85ff-58af-a436-5f6fa7bfa527,Tony Gonzales,Republican
|
||||
ocd-person/675e8a3b-ea68-55f8-aeb8-be287fe621bd,Tracey Mann,Republican
|
||||
ocd-person/c495bde9-29b3-5e71-ab0e-dedff0de9a84,Trent Kelly,Republican
|
||||
ocd-person/5e3dc0b5-2afe-5b83-ab42-9352225b2235,Troy A. Carter,Democratic
|
||||
ocd-person/7ba189b5-1c2a-5acd-8118-446326a8e02b,Troy Balderson,Republican
|
||||
ocd-person/ec5c60e6-2666-535c-a95a-ec6ab9e02e3f,Troy E. Nehls,Republican
|
||||
ocd-person/8d143b3d-646a-5199-95f5-497e17f386dd,Val T. Hoyle,Democratic
|
||||
ocd-person/2b138e95-2a83-5c51-a3f4-397017c9210e,Valerie P. Foushee,Democratic
|
||||
ocd-person/1e646f7b-600b-503f-9524-3ae95d00cd2d,Vern Buchanan,Republican
|
||||
ocd-person/a656d2f5-2e90-535c-91d9-d27ad1150c03,Veronica Escobar,Democratic
|
||||
ocd-person/8b1ad439-078b-5e79-a845-64236b87f11f,Vicente Gonzalez,Democratic
|
||||
ocd-person/bdb81964-c3cc-5f48-8854-7b9c88c23755,Victoria Spartz,Republican
|
||||
ocd-person/2d6b7f7f-a241-5064-9812-9506beb2b76e,Vince Fong,Republican
|
||||
ocd-person/b77761e4-93cb-5fbb-972e-5d591198df8f,Virginia Foxx,Republican
|
||||
ocd-person/5fdae4c2-ba21-56a4-ae8c-5e95a175a90a,W. Gregory Steube,Republican
|
||||
ocd-person/1eaeee77-2e74-51b9-a70f-30e16378f080,Warren Davidson,Republican
|
||||
ocd-person/2cb7c1ce-a9a1-5644-bfb8-14508d2d5f87,Wesley Hunt,Republican
|
||||
ocd-person/9866e387-b0c1-5f4d-b5da-dbde28ac482a,Wiley Nickel,Democratic
|
||||
ocd-person/ec0f62a4-5b85-5df2-888a-200166766b17,William R. Keating,Democratic
|
||||
ocd-person/678a7e1c-3834-5536-937f-fdb30edca68e,William R. Timmons IV,Republican
|
||||
ocd-person/4e28b856-d0c9-53f7-8dbd-bb9c6b99f145,Yadira Caraveo,Democratic
|
||||
ocd-person/34a22a9d-abf9-5e79-91f5-e4e08be6d2c9,Young Kim,Republican
|
||||
ocd-person/969d3e67-5686-5b4c-a8fe-5ec702a7343d,Yvette D. Clarke,Democratic
|
||||
ocd-person/144ba1b8-981f-58d8-b85d-c38fca7d524c,Zachary Nunn,Republican
|
||||
ocd-person/80764021-2b87-5b48-8999-98943700dea8,Zoe Lofgren,Democratic
|
|
@ -5,6 +5,10 @@ description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"altair>=5.5.0",
|
||||
"jupyter>=1.1.1",
|
||||
"pandas>=2.2.3",
|
||||
"polars>=1.16.0",
|
||||
"pyarrow>=18.1.0",
|
||||
"ruff>=0.6.8",
|
||||
]
|
||||
|
204242
sponsorships.csv
Normal file
204242
sponsorships.csv
Normal file
File diff suppressed because it is too large
Load Diff
221
uv.lock
generated
221
uv.lock
generated
@ -1,21 +1,50 @@
|
||||
version = 1
|
||||
requires-python = ">=3.10"
|
||||
resolution-markers = [
|
||||
"python_full_version < '3.11'",
|
||||
"python_full_version == '3.11.*'",
|
||||
"python_full_version >= '3.12'",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "51042-notes"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "altair" },
|
||||
{ name = "jupyter" },
|
||||
{ name = "pandas" },
|
||||
{ name = "polars" },
|
||||
{ name = "pyarrow" },
|
||||
{ name = "ruff" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "altair", specifier = ">=5.5.0" },
|
||||
{ name = "jupyter", specifier = ">=1.1.1" },
|
||||
{ name = "pandas", specifier = ">=2.2.3" },
|
||||
{ name = "polars", specifier = ">=1.16.0" },
|
||||
{ name = "pyarrow", specifier = ">=18.1.0" },
|
||||
{ name = "ruff", specifier = ">=0.6.8" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "altair"
|
||||
version = "5.5.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "jinja2" },
|
||||
{ name = "jsonschema" },
|
||||
{ name = "narwhals" },
|
||||
{ name = "packaging" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.14'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/16/b1/f2969c7bdb8ad8bbdda031687defdce2c19afba2aa2c8e1d2a17f78376d8/altair-5.5.0.tar.gz", hash = "sha256:d960ebe6178c56de3855a68c47b516be38640b73fb3b5111c2a9ca90546dd73d", size = 705305 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/f3/0b6ced594e51cc95d8c1fc1640d3623770d01e4969d29c0bd09945fafefa/altair-5.5.0-py3-none-any.whl", hash = "sha256:91a310b926508d560fe0148d02a194f38b824122641ef528113d029fcd129f8c", size = 731200 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.6.0"
|
||||
@ -830,6 +859,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/74/c95adcdf032956d9ef6c89a9b8a5152bf73915f8c633f3e3d88d06bd699c/mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205", size = 47958 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "narwhals"
|
||||
version = "1.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3f/62/331aa7414b58082fc5eaa81c70ef46ce096a06eeec25839189f970b8528f/narwhals-1.15.0.tar.gz", hash = "sha256:913e94afa453c661767186973c261998b1d8a14c223d6685f471ad149f62fb11", size = 197680 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/13/7c56859b34172ef1eba09cea82ea6afd614d90fc4ea60184656491221071/narwhals-1.15.0-py3-none-any.whl", hash = "sha256:f644cf70e9bea083d2426c5255da80f4fd2d4da5fdea1bbd2f89717a3e7086f9", size = 231953 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nbclient"
|
||||
version = "0.10.0"
|
||||
@ -923,6 +961,68 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "2.1.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/25/ca/1166b75c21abd1da445b97bf1fa2f14f423c6cfb4fc7c4ef31dccf9f6a94/numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761", size = 20166090 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/80/d572a4737626372915bca41c3afbfec9d173561a39a0a61bacbbfd1dafd4/numpy-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c894b4305373b9c5576d7a12b473702afdf48ce5369c074ba304cc5ad8730dff", size = 21152472 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/bb/7bfba10c791ae3bb6716da77ad85a82d5fac07fc96fb0023ef0571df9d20/numpy-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b47fbb433d3260adcd51eb54f92a2ffbc90a4595f8970ee00e064c644ac788f5", size = 13747967 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/d6/2df7bde35f0478455f0be5934877b3e5a505f587b00230f54a519a6b55a5/numpy-2.1.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:825656d0743699c529c5943554d223c021ff0494ff1442152ce887ef4f7561a1", size = 5354921 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/bb/75b945874f931494891eac6ca06a1764d0e8208791f3addadb2963b83527/numpy-2.1.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a4825252fcc430a182ac4dee5a505053d262c807f8a924603d411f6718b88fd", size = 6888603 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/a7/fde73636f6498dbfa6d82fc336164635fe592f1ad0d13285fcb6267fdc1c/numpy-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e711e02f49e176a01d0349d82cb5f05ba4db7d5e7e0defd026328e5cfb3226d3", size = 13889862 },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/db/5d9c91b2e1e2e72be1369278f696356d44975befcae830daf2e667dcb54f/numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098", size = 16328151 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/6a/7eb732109b53ae64a29e25d7e68eb9d6611037f6354875497008a49e74d3/numpy-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c7662f0e3673fe4e832fe07b65c50342ea27d989f92c80355658c7f888fcc83c", size = 16704107 },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/cc/278113b66a1141053cbda6f80e4200c6da06b3079c2d27bda1fde41f2c1f/numpy-2.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fa2d1337dc61c8dc417fbccf20f6d1e139896a30721b7f1e832b2bb6ef4eb6c4", size = 14385789 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/69/eb20f5e1bfa07449bc67574d2f0f7c1e6b335fb41672e43861a7727d85f2/numpy-2.1.3-cp310-cp310-win32.whl", hash = "sha256:72dcc4a35a8515d83e76b58fdf8113a5c969ccd505c8a946759b24e3182d1f23", size = 6536706 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/8b/1c131ab5a94c1086c289c6e1da1d843de9dbd95fe5f5ee6e61904c9518e2/numpy-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:ecc76a9ba2911d8d37ac01de72834d8849e55473457558e12995f4cd53e778e0", size = 12864165 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/81/c8167192eba5247593cd9d305ac236847c2912ff39e11402e72ae28a4985/numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d", size = 21156252 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/74/5a60003fc3d8a718d830b08b654d0eea2d2db0806bab8f3c2aca7e18e010/numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41", size = 13784119 },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/7c/864cb966b96fce5e63fcf25e1e4d957fe5725a635e5f11fe03f39dd9d6b5/numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9", size = 5352978 },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/ac/61d07930a4993dd9691a6432de16d93bbe6aa4b1c12a5e573d468eefc1ca/numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09", size = 6892570 },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/2f/21b94664f23af2bb52030653697c685022119e0dc93d6097c3cb45bce5f9/numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a", size = 13896715 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/f0/80811e836484262b236c684a75dfc4ba0424bc670e765afaa911468d9f39/numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b", size = 16339644 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/81/ce213159a1ed8eb7d88a2a6ef4fbdb9e4ffd0c76b866c350eb4e3c37e640/numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee", size = 16712217 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/84/4de0b87d5a72f45556b2a8ee9fc8801e8518ec867fc68260c1f5dcb3903f/numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0", size = 14399053 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/1c/e5fabb9ad849f9d798b44458fd12a318d27592d4bc1448e269dec070ff04/numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9", size = 6534741 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/48/a9a4b538e28f854bfb62e1dea3c8fea12e90216a276c7777ae5345ff29a7/numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2", size = 12869487 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/f0/385eb9970309643cbca4fc6eebc8bb16e560de129c91258dfaa18498da8b/numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e", size = 20849658 },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/4a/765b4607f0fecbb239638d610d04ec0a0ded9b4951c56dc68cef79026abf/numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958", size = 13492258 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/a7/2332679479c70b68dccbf4a8eb9c9b5ee383164b161bee9284ac141fbd33/numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8", size = 5090249 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/67/4aa00316b3b981a822c7a239d3a8135be2a6945d1fd11d0efb25d361711a/numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564", size = 6621704 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/da/1a429ae58b3b6c364eeec93bf044c532f2ff7b48a52e41050896cf15d5b1/numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512", size = 13606089 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/3e/3757f304c704f2f0294a6b8340fcf2be244038be07da4cccf390fa678a9f/numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b", size = 16043185 },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/97/75329c28fea3113d00c8d2daf9bc5828d58d78ed661d8e05e234f86f0f6d/numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc", size = 16410751 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/7a/442965e98b34e0ae9da319f075b387bcb9a1e0658276cc63adb8c9686f7b/numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0", size = 14082705 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/b6/26108cf2cfa5c7e03fb969b595c93131eab4a399762b51ce9ebec2332e80/numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9", size = 6239077 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/84/fa11dad3404b7634aaab50733581ce11e5350383311ea7a7010f464c0170/numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a", size = 12566858 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/0b/620591441457e25f3404c8057eb924d04f161244cb8a3680d529419aa86e/numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f", size = 20836263 },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/e1/210b2d8b31ce9119145433e6ea78046e30771de3fe353f313b2778142f34/numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598", size = 13507771 },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/44/aa9ee3caee02fa5a45f2c3b95cafe59c44e4b278fbbf895a93e88b308555/numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57", size = 5075805 },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/d6/61de6e7e31915ba4d87bbe1ae859e83e6582ea14c6add07c8f7eefd8488f/numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe", size = 6608380 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/46/48bdf9b7241e317e6cf94276fe11ba673c06d1fdf115d8b4ebf616affd1a/numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43", size = 13602451 },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/50/73f9a5aa0810cdccda9c1d20be3cbe4a4d6ea6bfd6931464a44c95eef731/numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56", size = 16039822 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/cd/098bc1d5a5bc5307cfc65ee9369d0ca658ed88fbd7307b0d49fab6ca5fa5/numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a", size = 16411822 },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/a2/7d4467a2a6d984549053b37945620209e702cf96a8bc658bc04bba13c9e2/numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef", size = 14079598 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/6a/d64514dcecb2ee70bfdfad10c42b76cab657e7ee31944ff7a600f141d9e9/numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f", size = 6236021 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/f9/12297ed8d8301a401e7d8eb6b418d32547f1d700ed3c038d325a605421a4/numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed", size = 12560405 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/45/7f9244cd792e163b334e3a7f02dff1239d2890b6f37ebf9e82cbe17debc0/numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f", size = 20859062 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/b4/a084218e7e92b506d634105b13e27a3a6645312b93e1c699cc9025adb0e1/numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4", size = 13515839 },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/45/58ed3f88028dcf80e6ea580311dc3edefdd94248f5770deb980500ef85dd/numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e", size = 5116031 },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/a8/eb689432eb977d83229094b58b0f53249d2209742f7de529c49d61a124a0/numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0", size = 6629977 },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/a3/5355ad51ac73c23334c7caaed01adadfda49544f646fcbfbb4331deb267b/numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408", size = 13575951 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/70/ea9646d203104e647988cb7d7279f135257a6b7e3354ea6c56f8bafdb095/numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6", size = 16022655 },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/ce/7fc0612903e91ff9d0b3f2eda4e18ef9904814afcae5b0f08edb7f637883/numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f", size = 16399902 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/62/1d3204313357591c913c32132a28f09a26357e33ea3c4e2fe81269e0dca1/numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17", size = 14067180 },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/d7/78a40ed1d80e23a774cb8a34ae8a9493ba1b4271dde96e56ccdbab1620ef/numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48", size = 6291907 },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/09/a5ab407bd7f5f5599e6a9261f964ace03a73e7c6928de906981c31c38082/numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4", size = 12644098 },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/e7/8d8bb791b62586cc432ecbb70632b4f23b7b7c88df41878de7528264f6d7/numpy-2.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4f2015dfe437dfebbfce7c85c7b53d81ba49e71ba7eadbf1df40c915af75979f", size = 20983893 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/f3/cb8118a044b5007586245a650360c9f5915b2f4232dd7658bb7a63dd1d02/numpy-2.1.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3522b0dfe983a575e6a9ab3a4a4dfe156c3e428468ff08ce582b9bb6bd1d71d4", size = 6752501 },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/f5/365b46439b518d2ec6ebb880cc0edf90f225145dfd4db7958334f7164530/numpy-2.1.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006b607a865b07cd981ccb218a04fc86b600411d83d6fc261357f1c0966755d", size = 16142601 },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/c2/d1fee6ba999aa7cd41ca6856937f2baaf604c3eec1565eae63451ec31e5e/numpy-2.1.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e14e26956e6f1696070788252dcdff11b4aca4c3e8bd166e0df1bb8f315a67cb", size = 12771397 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overrides"
|
||||
version = "7.7.0"
|
||||
@ -941,6 +1041,54 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pandas"
|
||||
version = "2.2.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "numpy" },
|
||||
{ name = "python-dateutil" },
|
||||
{ name = "pytz" },
|
||||
{ name = "tzdata" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/70/c853aec59839bceed032d52010ff5f1b8d87dc3114b762e4ba2727661a3b/pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", size = 12580827 },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/f2/c4527768739ffa4469b2b4fff05aa3768a478aed89a2f271a79a40eee984/pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", size = 11303897 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/12/86c1747ea27989d7a4064f806ce2bae2c6d575b950be087837bdfcabacc9/pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", size = 66480908 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/50/7db2cd5e6373ae796f0ddad3675268c8d59fb6076e66f0c339d61cea886b/pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", size = 13064210 },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/61/a89015a6d5536cb0d6c3ba02cebed51a95538cf83472975275e28ebf7d0c/pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", size = 16754292 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/0d/4cc7b69ce37fac07645a94e1d4b0880b15999494372c1523508511b09e40/pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", size = 14416379 },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/9e/6ebb433de864a6cd45716af52a4d7a8c3c9aaf3a98368e61db9e69e69a9c/pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", size = 11598471 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/44/d9502bf0ed197ba9bf1103c9867d5904ddcaf869e52329787fc54ed70cc8/pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", size = 12602222 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/11/9eac327a38834f162b8250aab32a6781339c69afe7574368fffe46387edf/pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", size = 11321274 },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/fb/c4beeb084718598ba19aa9f5abbc8aed8b42f90930da861fcb1acdb54c3a/pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", size = 15579836 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/5f/4dba1d39bb9c38d574a9a22548c540177f78ea47b32f99c0ff2ec499fac5/pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", size = 13058505 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/57/708135b90391995361636634df1f1130d03ba456e95bcf576fada459115a/pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", size = 16744420 },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/4a/03ed6b7ee323cf30404265c284cee9c65c56a212e0a08d9ee06984ba2240/pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", size = 14440457 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/8c/87ddf1fcb55d11f9f847e3c69bb1c6f8e46e2f40ab1a2d2abadb2401b007/pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", size = 11617166 },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", size = 12529893 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", size = 11363475 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", size = 15188645 },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", size = 12739445 },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756 },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248 },
|
||||
{ url = "https://files.pythonhosted.org/packages/64/22/3b8f4e0ed70644e85cfdcd57454686b9057c6c38d2f74fe4b8bc2527214a/pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", size = 12477643 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/93/b3f5d1838500e22c8d793625da672f3eec046b1a99257666c94446969282/pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", size = 11281573 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/94/6c79b07f0e5aab1dcfa35a75f4817f5c4f677931d4234afcd75f0e6a66ca/pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", size = 15196085 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/31/aa8da88ca0eadbabd0a639788a6da13bb2ff6edbbb9f29aa786450a30a91/pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", size = 12711809 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/7c/c6dbdb0cb2a4344cacfb8de1c5808ca885b2e4dcfde8008266608f9372af/pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", size = 16356316 },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/b7/8b757e7d92023b832869fa8881a992696a0bfe2e26f72c9ae9f255988d42/pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", size = 14022055 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/bc/4b18e2b8c002572c5a441a64826252ce5da2aa738855747247a971988043/pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", size = 11481175 },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/a3/a5d88146815e972d40d19247b2c162e88213ef51c7c25993942c39dbf41d/pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", size = 12615650 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/8c/f0fd18f6140ddafc0c24122c8a964e48294acc579d47def376fef12bcb4a/pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", size = 11290177 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/f9/e995754eab9c0f14c6777401f7eece0943840b7a9fc932221c19d1abee9f/pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", size = 14651526 },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/b0/98d6ae2e1abac4f35230aa756005e8654649d305df9a28b16b9ae4353bff/pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", size = 11871013 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/57/0f72a10f9db6a4628744c8e8f0df4e6e21de01212c7c981d31e50ffc8328/pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", size = 15711620 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/5f/b38085618b950b79d2d9164a711c52b10aefc0ae6833b96f626b7021b2ed/pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", size = 13098436 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pandocfilters"
|
||||
version = "1.5.1"
|
||||
@ -980,6 +1128,19 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polars"
|
||||
version = "1.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/80/d845897273be97a3e73b59be711deda375b638330d591a7ef8132c20f52f/polars-1.16.0.tar.gz", hash = "sha256:dd99808b833872babe02434a809fd45c1cffe66a3d57123cdc5e447c7753d328", size = 4192568 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/b0/51c944ecd58b3ebc81eb03b50448127ff85fd9448063094524e0c6693c75/polars-1.16.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:072f5ff3b5fe05797c59890de0e464b34ede75a9735e7d7221622fa3a0616d8e", size = 34735038 },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/2f/d0b45007f2ae4b4926070b420c8525840b9757013cd96077bcde40807ecb/polars-1.16.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ebaf7a1ea114b042fa9f1cd17d49436279eb30545dd74361a2f5e3febeb867cd", size = 30577461 },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/9e/21e05959323883abcee799837d8cac08adf10a48c233432993757e41791a/polars-1.16.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e626d21dcd2566e1442dac414fe177bc70ebfc2f16620d59d778b1b774361018", size = 36006233 },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/80/da5c3cd248c7642d1feb896f0a27a0860c607f8cdde3e75457182e4c76c6/polars-1.16.0-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:53debcce55f68731ee2c7d6c787afdee26860ed6576f1ffa0cb9111b57f82857", size = 32348398 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/0b/677c905f9dd5bc37708694e8f7367659c5382bd011f5dc1d564474032d0b/polars-1.16.0-cp39-abi3-win_amd64.whl", hash = "sha256:17efcb550c42d51034ff79702612b9184d8eac0d500de1dd7fb98490459276d3", size = 35743314 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometheus-client"
|
||||
version = "0.21.0"
|
||||
@ -1036,6 +1197,48 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyarrow"
|
||||
version = "18.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7f/7b/640785a9062bb00314caa8a387abce547d2a420cf09bd6c715fe659ccffb/pyarrow-18.1.0.tar.gz", hash = "sha256:9386d3ca9c145b5539a1cfc75df07757dff870168c959b473a0bccbc3abc8c73", size = 1118671 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/bb/8d4a1573f66e0684f190dd2b55fd0b97a7214de8882d58a3867e777bf640/pyarrow-18.1.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e21488d5cfd3d8b500b3238a6c4b075efabc18f0f6d80b29239737ebd69caa6c", size = 29531620 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/90/893acfad917533b624a97b9e498c0e8393908508a0a72d624fe935e632bf/pyarrow-18.1.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:b516dad76f258a702f7ca0250885fc93d1fa5ac13ad51258e39d402bd9e2e1e4", size = 30836521 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/2a/526545a7464b5fb2fa6e2c4bad16ca90e59e1843025c534fd907b7f73e5a/pyarrow-18.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f443122c8e31f4c9199cb23dca29ab9427cef990f283f80fe15b8e124bcc49b", size = 39213905 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/77/4b3fab91a30e19e233e738d0c5eca5a8f6dd05758bc349a2ca262c65de79/pyarrow-18.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a03da7f2758645d17b7b4f83c8bffeae5bbb7f974523fe901f36288d2eab71", size = 40128881 },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/e2/a88e16c5e45e562449c52305bd3bc2f9d704295322d3434656e7ccac1444/pyarrow-18.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ba17845efe3aa358ec266cf9cc2800fa73038211fb27968bfa88acd09261a470", size = 38627517 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/84/8037c20005ccc7b869726465be0957bd9c29cfc88612962030f08292ad06/pyarrow-18.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3c35813c11a059056a22a3bef520461310f2f7eea5c8a11ef9de7062a23f8d56", size = 40060187 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/38/d6435c723ff73df8ae74626ea778262fbcc2b9b0d1a4f3db915b61711b05/pyarrow-18.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9736ba3c85129d72aefa21b4f3bd715bc4190fe4426715abfff90481e7d00812", size = 25118314 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/4d/a4988e7d82f4fbc797715db4185939a658eeffb07a25bab7262bed1ea076/pyarrow-18.1.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:eaeabf638408de2772ce3d7793b2668d4bb93807deed1725413b70e3156a7854", size = 29554860 },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/03/3a42c5c1e4bd4c900ab62aa1ff6b472bdb159ba8f1c3e5deadab7222244f/pyarrow-18.1.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:3b2e2239339c538f3464308fd345113f886ad031ef8266c6f004d49769bb074c", size = 30867076 },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/7e/332055ac913373e89256dce9d14b7708f55f7bd5be631456c897f0237738/pyarrow-18.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f39a2e0ed32a0970e4e46c262753417a60c43a3246972cfc2d3eb85aedd01b21", size = 39212135 },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/64/5099cdb325828722ef7ffeba9a4696f238eb0cdeae227f831c2d77fcf1bd/pyarrow-18.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31e9417ba9c42627574bdbfeada7217ad8a4cbbe45b9d6bdd4b62abbca4c6f6", size = 40125195 },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/88/1938d783727db1b178ff71bc6a6143d7939e406db83a9ec23cad3dad325c/pyarrow-18.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:01c034b576ce0eef554f7c3d8c341714954be9b3f5d5bc7117006b85fcf302fe", size = 38641884 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/b5/9e14e9f7590e0eaa435ecea84dabb137284a4dbba7b3c337b58b65b76d95/pyarrow-18.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:f266a2c0fc31995a06ebd30bcfdb7f615d7278035ec5b1cd71c48d56daaf30b0", size = 40076877 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/a3/817ac7fe0891a2d66e247e223080f3a6a262d8aefd77e11e8c27e6acf4e1/pyarrow-18.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d4f13eee18433f99adefaeb7e01d83b59f73360c231d4782d9ddfaf1c3fbde0a", size = 25119811 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/50/12829e7111b932581e51dda51d5cb39207a056c30fe31ef43f14c63c4d7e/pyarrow-18.1.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:9f3a76670b263dc41d0ae877f09124ab96ce10e4e48f3e3e4257273cee61ad0d", size = 29514620 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/41/468c944eab157702e96abab3d07b48b8424927d4933541ab43788bb6964d/pyarrow-18.1.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:da31fbca07c435be88a0c321402c4e31a2ba61593ec7473630769de8346b54ee", size = 30856494 },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/f9/29fb659b390312a7345aeb858a9d9c157552a8852522f2c8bad437c29c0a/pyarrow-18.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:543ad8459bc438efc46d29a759e1079436290bd583141384c6f7a1068ed6f992", size = 39203624 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/f6/19360dae44200e35753c5c2889dc478154cd78e61b1f738514c9f131734d/pyarrow-18.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0743e503c55be0fdb5c08e7d44853da27f19dc854531c0570f9f394ec9671d54", size = 40139341 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/e6/9b3afbbcf10cc724312e824af94a2e993d8ace22994d823f5c35324cebf5/pyarrow-18.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d4b3d2a34780645bed6414e22dda55a92e0fcd1b8a637fba86800ad737057e33", size = 38618629 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/2e/3b99f8a3d9e0ccae0e961978a0d0089b25fb46ebbcfb5ebae3cca179a5b3/pyarrow-18.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c52f81aa6f6575058d8e2c782bf79d4f9fdc89887f16825ec3a66607a5dd8e30", size = 40078661 },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/52/f8da04195000099d394012b8d42c503d7041b79f778d854f410e5f05049a/pyarrow-18.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ad4892617e1a6c7a551cfc827e072a633eaff758fa09f21c4ee548c30bcaf99", size = 25092330 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/87/aa4d249732edef6ad88899399047d7e49311a55749d3c373007d034ee471/pyarrow-18.1.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:84e314d22231357d473eabec709d0ba285fa706a72377f9cc8e1cb3c8013813b", size = 29497406 },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/c7/ed6adb46d93a3177540e228b5ca30d99fc8ea3b13bdb88b6f8b6467e2cb7/pyarrow-18.1.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:f591704ac05dfd0477bb8f8e0bd4b5dc52c1cadf50503858dce3a15db6e46ff2", size = 30835095 },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/d7/ed85001edfb96200ff606943cff71d64f91926ab42828676c0fc0db98963/pyarrow-18.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acb7564204d3c40babf93a05624fc6a8ec1ab1def295c363afc40b0c9e66c191", size = 39194527 },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/16/35e28eab126342fa391593415d79477e89582de411bb95232f28b131a769/pyarrow-18.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74de649d1d2ccb778f7c3afff6085bd5092aed4c23df9feeb45dd6b16f3811aa", size = 40131443 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/95/e855880614c8da20f4cd74fa85d7268c725cf0013dc754048593a38896a0/pyarrow-18.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f96bd502cb11abb08efea6dab09c003305161cb6c9eafd432e35e76e7fa9b90c", size = 38608750 },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/9d/f253554b1457d4fdb3831b7bd5f8f00f1795585a606eabf6fec0a58a9c38/pyarrow-18.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:36ac22d7782554754a3b50201b607d553a8d71b78cdf03b33c1125be4b52397c", size = 40066690 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/58/8912a2563e6b8273e8aa7b605a345bba5a06204549826f6493065575ebc0/pyarrow-18.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:25dbacab8c5952df0ca6ca0af28f50d45bd31c1ff6fcf79e2d120b4a65ee7181", size = 25081054 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/f9/d06ddc06cab1ada0c2f2fd205ac8c25c2701182de1b9c4bf7a0a44844431/pyarrow-18.1.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6a276190309aba7bc9d5bd2933230458b3521a4317acfefe69a354f2fe59f2bc", size = 29525542 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/94/8917e3b961810587ecbdaa417f8ebac0abb25105ae667b7aa11c05876976/pyarrow-18.1.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:ad514dbfcffe30124ce655d72771ae070f30bf850b48bc4d9d3b25993ee0e386", size = 30829412 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/e3/3b16c3190f3d71d3b10f6758d2d5f7779ef008c4fd367cedab3ed178a9f7/pyarrow-18.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aebc13a11ed3032d8dd6e7171eb6e86d40d67a5639d96c35142bd568b9299324", size = 39119106 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/d6/5d704b0d25c3c79532f8c0639f253ec2803b897100f64bcb3f53ced236e5/pyarrow-18.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6cf5c05f3cee251d80e98726b5c7cc9f21bab9e9783673bac58e6dfab57ecc8", size = 40090940 },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/29/366bc7e588220d74ec00e497ac6710c2833c9176f0372fe0286929b2d64c/pyarrow-18.1.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:11b676cd410cf162d3f6a70b43fb9e1e40affbc542a1e9ed3681895f2962d3d9", size = 38548177 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/11/fabf6ecabb1fe5b7d96889228ca2a9158c4c3bb732e3b8ee3f7f6d40b703/pyarrow-18.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:b76130d835261b38f14fc41fdfb39ad8d672afb84c447126b84d5472244cfaba", size = 40043567 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.22"
|
||||
@ -1075,6 +1278,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd", size = 8067 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2024.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3a/31/3c70bf7603cc2dca0f19bdc53b4537a797747a58875b552c8c413d963a3f/pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", size = 319692 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725", size = 508002 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pywin32"
|
||||
version = "306"
|
||||
@ -1503,6 +1715,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2024.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e1/34/943888654477a574a86a98e9896bae89c7aa15078ec29f490fef2f1e5384/tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", size = 193282 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd", size = 346586 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uri-template"
|
||||
version = "1.3.0"
|
||||
|
Loading…
Reference in New Issue
Block a user