From 461e9b20842fac1e6b3855c98577acb8277dba81 Mon Sep 17 00:00:00 2001 From: John McGarvey Date: Thu, 9 Jan 2025 13:55:11 -0500 Subject: [PATCH 01/27] first commit --- .gitignore | 8 ++++++++ README.md | 35 +++++++++++++++++++++++++++++++++++ requirements_dev.txt | 1 + 3 files changed, 44 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 requirements_dev.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c07589 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.idea ++.DS_Store* +.pytest_cache +__pycache__/ +*.rb +.vscode +CACHEDIR.TAG +.venv/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a301b66 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# Repository for Code the Dream Python 100 Homework + +Before using this repository, you should install Python. + +If you are using the VSCode editor, you should also have installed the Python extension. (You may use a different editor, such as JetBrains Pycharm, but the instructions here describe the use of VSCode.) If you are on Windows, you should configure VSCode to use Git Bash for your terminal session. This is done from the command palette `Terminal: Select Default Profile`. + + You should also have done the command: +```shell +pip install virtualenv +``` + +To use this repository: + +1. Fork this repository, to create a copy in your Github account. +2. On your laptop, clone your fork. (Do not clone the original repository!) +3. Change to the python_homework directory. Enter the following commands: +```shell +pip -m venv .venv +code . +``` +4. Important: Open the VSCode command pallette (ctrl-shift P). In the `Python: Select Interpreter` option, choose the one with `.venv`. If you have any terminal sessions open, close them, and open a new one. You will see `(venv)` in your terminal prompt. +5. From the VSCode terminal session, enter the command: +```shell +pip install -r requirements_dev.txt +``` + +Once this is done, you are ready to create your lesson1 git branch. You create a separate branch for each lesson. The lesson2 branch is created when the lesson1 branch is active, so that the lessons build on one another. + +Create the programs for lesson 1. These are to be created in the root of your python_homework repository, unless the lesson specifies otherwise. In some cases, you will need to install additional pip packages to complete the lesson. + +When you have completed the lesson, add and commit your changes and push them to your fork of this repository. Then create a pull request. **Be careful here!** The target for your pull request must be the main branch of YOUR repository. The default target that comes up when you create the pull request is this repository in the Code The Dream School account. **You don't want to use the default target.** Many students make this error. + +Once you have created the pull request, include a link for the pull request in your homework submission. Your reviewer will be notified, and will approve your request or ask for rework. **Do not merge your pull request until your reviewer has approved it.** + +Good luck with the class! \ No newline at end of file diff --git a/requirements_dev.txt b/requirements_dev.txt new file mode 100644 index 0000000..55b033e --- /dev/null +++ b/requirements_dev.txt @@ -0,0 +1 @@ +pytest \ No newline at end of file From 0b2ec6cd9e227e6d2a4175e2592c380fe5b15b58 Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Thu, 30 Jan 2025 18:58:27 -0500 Subject: [PATCH 02/27] add sample database --- .gitattributes | 1 + README.md | 38 +- csv/customers.csv | 101 ++++ csv/employees.csv | 21 + csv/line_items.csv | 1110 ++++++++++++++++++++++++++++++++++++++++++ csv/orders.csv | 250 ++++++++++ csv/products.csv | 60 +++ db/.gitignore | 2 + load_db.py | 77 +++ requirements.txt | 6 + requirements_dev.txt | 1 - sqlcommand.py | 68 +++ 12 files changed, 1718 insertions(+), 17 deletions(-) create mode 100644 .gitattributes create mode 100644 csv/customers.csv create mode 100644 csv/employees.csv create mode 100644 csv/line_items.csv create mode 100644 csv/orders.csv create mode 100644 csv/products.csv create mode 100644 db/.gitignore create mode 100644 load_db.py create mode 100644 requirements.txt delete mode 100644 requirements_dev.txt create mode 100644 sqlcommand.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..44fcab8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.ipynb filter=nbstripout \ No newline at end of file diff --git a/README.md b/README.md index a301b66..8f84e27 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,40 @@ # Repository for Code the Dream Python 100 Homework -Before using this repository, you should install Python. - -If you are using the VSCode editor, you should also have installed the Python extension. (You may use a different editor, such as JetBrains Pycharm, but the instructions here describe the use of VSCode.) If you are on Windows, you should configure VSCode to use Git Bash for your terminal session. This is done from the command palette `Terminal: Select Default Profile`. - - You should also have done the command: -```shell -pip install virtualenv -``` +Before using this repository, you must install Python and must complete the rest of the setup as described in Python Essentials Lesson 1. Several steps are needed to configure VSCode, and you need to have installed the virtualenv pip package. To use this repository: -1. Fork this repository, to create a copy in your Github account. -2. On your laptop, clone your fork. (Do not clone the original repository!) +1. Sign into your GitHub, and create a repository called python_homework. It must be a public repository. Do not create a .gitignore or a README.md. +2. On your laptop, clone the [https://github.com/Code-the-Dream-School/python_homework](https://github.com/Code-the-Dream-School/python_homework) repository. (Do not clone the repository you just created.) 3. Change to the python_homework directory. Enter the following commands: ```shell -pip -m venv .venv +git remote set-url origin https://github.com/your-github-id/python_homework +git remote add upstream https://github.com/Code-the-Dream-School/python_homework +git push origin main +``` +4. While still within the python_homework directory, enter the following commands: +```shell +python -m venv .venv +source .venv/bin/activate +code . +``` +For some environments, you have to use the `python3` command. For Windows users, the command is different: +```shell +python -m venv .venv +source .venv/Scripts/activate code . ``` -4. Important: Open the VSCode command pallette (ctrl-shift P). In the `Python: Select Interpreter` option, choose the one with `.venv`. If you have any terminal sessions open, close them, and open a new one. You will see `(venv)` in your terminal prompt. +4. Important: Open the VSCode command pallette (ctrl-shift P). In the `Python: Select Interpreter` option, choose the one with `.venv`. If you have any terminal sessions open, close them, and open a new one. You will see `(.venv)` in your terminal prompt. 5. From the VSCode terminal session, enter the command: ```shell -pip install -r requirements_dev.txt +pip install -r requirements.txt ``` -Once this is done, you are ready to create your lesson1 git branch. You create a separate branch for each lesson. The lesson2 branch is created when the lesson1 branch is active, so that the lessons build on one another. +Once this is done, you are ready to create your assignment1 git branch. You create a separate branch for each lesson. The assignment2 branch is created when the assignment1 branch is active, so that the lessons build on one another. The files you create or modify for each assignment are described in the assignment itself. They are to be created in the root of your python_homework repository, unless the lesson specifies otherwise. -Create the programs for lesson 1. These are to be created in the root of your python_homework repository, unless the lesson specifies otherwise. In some cases, you will need to install additional pip packages to complete the lesson. +In some cases, you will need to install additional pip packages to complete the lesson. -When you have completed the lesson, add and commit your changes and push them to your fork of this repository. Then create a pull request. **Be careful here!** The target for your pull request must be the main branch of YOUR repository. The default target that comes up when you create the pull request is this repository in the Code The Dream School account. **You don't want to use the default target.** Many students make this error. +When you have completed the lesson, add and commit your changes and push them to your GitHub. Then create a pull request. Once you have created the pull request, include a link for the pull request in your homework submission. Your reviewer will be notified, and will approve your request or ask for rework. **Do not merge your pull request until your reviewer has approved it.** diff --git a/csv/customers.csv b/csv/customers.csv new file mode 100644 index 0000000..4ab941b --- /dev/null +++ b/csv/customers.csv @@ -0,0 +1,101 @@ +customer_id,customer_name,contact,street,city,country,postal_code,phone +1,"Short, Taylor and Brown",Andrew Woods,3104 Allen Mall,Scottton,Mauritania,91825,+82 +1-536-993-0030 +2,Glover-Hernandez,Kathleen Callahan,46716 Graves Drive,West Kimberg,Myanmar,75905,+234 447-861-4700x71251 +3,Conrad-Harris,Mark Hill,4945 Harvey Greens Suite 329,Matthewmouth,Northern Mariana Islands,23860,+262 639 691.737.9008 +4,Patterson-Smith,Russell Peterson,574 Harvey Vista Suite 020,Lake Tammyport,San Marino,75100,+373 2 001-230-218-0321x1805 +5,Mccann-Thompson,Jacob Myers,988 Brittney Walk Suite 803,New Rebecca,Albania,04586,+358 18 001-264-844-5618x991 +6,Kelly-Oconnell,Amber Harmon,5076 Pamela Estates,Lake Rachel,Malawi,59981,+39 06 698 262.613.2527 +7,"Stephens, King and Johnson",Amanda Walker,8142 Crawford Mission,Port Jonathanshire,Grenada,15468,+1 284 001-675-402-4532x8276 +8,Williams-Mack,Zachary Walker,24067 David Land,North Rickytown,Sri Lanka,23962,+420 (989)498-0714 +9,Clark-Brooks,Matthew Nguyen,852 Melton Fall,West Mariafurt,Turkey,35212,+57 (899)758-1468x885 +10,Galloway-Coleman,Sean Chang,64742 Darren Parkway,Matthewhaven,Nicaragua,71733,+216 001-669-730-9178 +11,"Mills, Torres and Graham",Matthew Rangel,521 Sampson Loop Suite 683,West Dawn,Algeria,85945,+507 366.980.7640 +12,Preston-Wright,Shawn Weber,18139 Christian Island Apt. 864,Richardfort,Senegal,29567,+211 6025619622 +13,Owens-Mclaughlin,Matthew Pierce,96172 Barbara Highway,Lisaside,Netherlands Antilles,40335,+356 (322)267-5055x817 +14,Dean Ltd,Benjamin Huber,2887 Mills Vista Apt. 076,North Lisa,Zambia,57988,+39 (306)239-8565 +15,Mills Inc,Gilbert Ramos,721 Barrett Path Apt. 626,Frankland,Libyan Arab Jamahiriya,27619,+596 +1-276-449-4908x293 +16,Perez and Sons,Margaret Gardner,279 Angie Circles,Lake Rebeccaborough,Maldives,03033,+882 16 702-415-0969x8783 +17,"Neal, Baxter and Thompson",Kristen Flynn MD,42153 Smith Plaza,Hallbury,Germany,53344,+39 9158142105 +18,Garcia-Mcgrath,John Johnson,19407 Gallagher Crossroad Suite 600,South Matthewland,Sudan,45340,+683 4684301465 +19,"Serrano, Armstrong and Taylor",Stacy Allen,494 Debra Land,Matthewborough,Guinea-Bissau,16386,+678 (234)657-2167x436 +20,Salas-Ruiz,Arthur Chavez,185 Lee Street Suite 551,Trevorfurt,Pakistan,04412,+1 664 +1-749-367-7829x2179 +21,Meyer Ltd,Lisa Patton,292 Hutchinson Court Apt. 294,Jillianfurt,Tonga,53888,+32 872.578.2697 +22,Williams-Higgins,David Robinson,6150 Jennifer Rue Apt. 594,West Peter,Nepal,17401,+888 (760)264-2789x3312 +23,"Davis, Salinas and Johnson",Maria Ali,2253 Robert Course,West Rachael,Norway,11260,+882 13 250-992-3486x06384 +24,Ross Ltd,April Lee,9927 Rangel Union,Brennanland,Pitcairn Islands,68459,+1 345 +1-990-442-2922 +25,Vasquez and Sons,Dominic Freeman,1997 Cohen Crossing Suite 001,South Daniel,New Caledonia,90989,+52 +1-460-874-7358 +26,Johnson Inc,Dennis Nielsen,346 Linda Plains Suite 250,New Julie,Tunisia,78450,+973 878-371-0298x9071 +27,Smith-Moore,Chris Kim,2952 Richardson Wells,Port Larry,Zambia,32492,+91 (359)757-9911 +28,Bryant-Hinton,Matthew Francis,81705 Jennifer Branch,Lake Robertview,Guinea-Bissau,01736,+686 370-603-2757 +29,"Reynolds, Pollard and Day",Cody Harrell,51011 Martinez Island,East Michael,Saint Helena,49122,+599 9 760-278-8510x36690 +30,"Weiss, Sanders and Clark",Alicia Doyle,82122 Keith Center,Brianashire,Afghanistan,15308,+92 001-636-335-4769 +31,"Lowe, Acevedo and Thompson",Heather Gutierrez,69013 Kelley Springs Apt. 481,Ronaldland,United Arab Emirates,23846,+590 +1-765-786-8831x539 +32,Chambers-Anderson,Victoria Ali,7284 Shane Ports Apt. 317,West Douglas,Guam,41321,+44 7924 (690)421-4096x407 +33,Delacruz-Powell,Evelyn Neal,6109 Dawn Cliff,South Cynthia,Bangladesh,59906,+256 001-786-917-7545x549 +34,Wise Group,Jeremy Holland,6905 Andrade Square,West Matthew,Austria,16337,+994 318.723.5942x03732 +35,Espinoza Inc,David Hudson,720 Amber Estate,Port Cassandraview,Sierra Leone,94780,+598 827.804.7412x684 +36,"Burke, Wilkerson and Coleman",Kim Davis MD,68999 Pierce Way Apt. 263,North Scott,Reunion,82849,+968 650-402-5555 +37,Cox-Moyer,Shannon Mccullough,007 David Avenue Suite 742,Campbellburgh,Cambodia,72332,+685 996-802-9411x841 +38,"Walsh, Costa and Oconnor",Christine Taylor,30328 Gregory Station Apt. 545,North Daniel,Spain,14265,+255 24 +1-553-492-1933x589 +39,"Ray, Shaw and Miller",Jason Rush,349 Rivera Rapid Apt. 628,Spencerland,Fiji,26741,+979 001-224-412-7788x646 +40,"Proctor, Cooley and Coleman",Melanie Woods,839 Mccormick Bridge,East John,Oman,76457,+590 (380)583-9156x7682 +41,Hogan Inc,Michael Jones,37445 Joseph Valley Suite 003,Jonmouth,Palestinian Territory,57860,+975 (948)612-0559x419 +42,"Phillips, Bush and Miller",Andrea Stevens,55310 Harris Springs,Schmidtmouth,Qatar,59359,+672 +1-261-295-9832x1971 +43,Solis Group,Tammy Walters,6393 Patricia Circles,North John,Brunei Darussalam,17162,+237 4783325433 +44,Esparza-Terry,Jason Dawson,21012 Brock Tunnel,Christinefurt,Palau,40098,+55 714-878-1327x79527 +45,"Bailey, Henderson and Bailey",Joshua Morgan,39079 Yoder Ridge,Martinezburgh,Austria,66784,+964 880.421.9411x37322 +46,Walters Inc,Eddie Olson,60648 Kaitlyn Ways,Erikfort,Bermuda,06185,+66 001-885-880-1386 +47,Johnson PLC,Glenda Gregory,09100 Greg Fields Suite 841,North Kayla,Serbia,01909,+970 490-988-7105 +48,Anderson and Sons,Abigail Riley,5846 Joseph Branch Apt. 487,Holdenchester,Saint Martin,10136,+299 669-515-9554x3928 +49,Powell Group,Shawn Cruz,27581 Lee Island,Codyberg,Ghana,49748,+223 609-203-8403 +50,"Hardy, Smith and Smith",Brian Stephens,3736 Harris Oval Apt. 027,Rileytown,Palestinian Territory,07020,+61 89164 343-410-8563x426 +51,Fox Inc,Terry Allen,2597 Antonio Locks Apt. 946,Garzaville,Central African Republic,37216,+500 438.443.9141 +52,Young-Cobb,Tammy Taylor,7877 Edwards Stravenue,New Wandachester,Luxembourg,50287,+881 1 001-574-923-7538x0257 +53,"Martin, Harris and Brooks",Jennifer Douglas,8304 Mia Court,Lake Carl,Isle of Man,98247,+290 783-894-7720 +54,Hodges and Sons,Karen Barron,6331 Cole Glen Apt. 945,Ariasfort,American Samoa,77767,+599 9 +1-808-423-4564x033 +55,Wilson Inc,Shawn Benjamin,154 Pollard Junction,Beckerfort,Ukraine,35477,+33 3632393107 +56,Saunders-Huffman,Andrea Foster,86832 Morrow Prairie,North Kelly,Somalia,75324,+234 729.843.1316x90623 +57,"Owens, Reese and Villa",Tyler Watson,267 Hart Drive Apt. 357,Brentport,Rwanda,22919,+211 5402700198 +58,Schroeder Ltd,Mike Baldwin,38983 Jason Square Suite 828,North Dustinmouth,Trinidad and Tobago,26171,+1 784 (432)493-4710x7366 +59,"Frazier, Brooks and Ramirez",Karla Church,333 Jill Alley Suite 373,West Paul,Malaysia,86114,+881 6 001-690-676-5097x1557 +60,"Barber, Warner and Moon",Jay Stone,576 Meghan Groves,Patriciaville,Burkina Faso,77025,+687 (908)791-0226x4365 +61,Conner-Cunningham,Gregory Benjamin,506 Richard Road Apt. 608,Richardsmouth,Oman,05983,+878 (889)917-8446 +62,Jordan Ltd,Jonathan Anderson,08205 Trevino Extensions,Erinshire,Mongolia,73172,+881 9 +1-378-478-0918x277 +63,Dennis Group,Craig Lee,82763 Melendez Underpass,Port Ryan,Saint Helena,31457,+359 +1-970-903-0707x31839 +64,Wall-Mcmillan,Joseph Martin,883 Jamie Forge Apt. 064,Aliciaberg,Guadeloupe,83751,+240 335.817.2866 +65,Smith-Walker,Michael White,0118 Hubbard Center,Jasonburgh,Tanzania,86309,+420 707-654-5891 +66,Graham Inc,Amber Allen,578 Alyssa Mission Suite 337,Careytown,Cuba,26775,+670 472.311.5090x63460 +67,Williams LLC,Charles Berger,59807 Nunez Ports,Evansstad,Tonga,19622,+86 553-685-4446x005 +68,"Brooks, Cox and Martin",Ariana Murphy,508 Veronica Parkway Apt. 411,Carrollshire,Ukraine,91146,+504 572.871.1204x32747 +69,Johnson-Dillon,Dawn Tanner,16284 Marcus Road Apt. 687,Hammondstad,Heard Island and McDonald Islands,09847,+90 392 410-249-4779 +70,Sullivan Ltd,Maria Massey,8808 Reyes Plains,Sullivanfurt,British Virgin Islands,30660,+64 614.901.7994x8695 +71,Collins-Cabrera,Tony Olsen,01686 Christopher Flats,Yolandafort,Chile,76327,+963 507.706.7176x72538 +72,Snyder-Ward,Vincent Nunez,33923 Hernandez Ridge Apt. 431,Brownfurt,Bulgaria,88381,+257 (935)568-2730 +73,"Ramsey, Buchanan and Berger",Lee Welch,166 Ashley Rapids Apt. 508,East Brian,Papua New Guinea,14997,+239 969-816-1425x5451 +74,"Callahan, Melendez and Brooks",Lisa Ramsey,80540 Mike Corners,Gallaghermouth,Timor-Leste,05763,+881 7 864-849-0165x383 +75,Rodriguez-Smith,Haley Jackson,13865 Leah Shoals,Daniellebury,Singapore,88899,+262 639 (656)266-9976x155 +76,Rivera Group,Danielle Small,7504 Michael Forges,Lake Scottside,Peru,10107,+66 334-271-4947x543 +77,Moss LLC,Teresa French,358 Hawkins Cape Suite 179,Port Jamesfurt,Equatorial Guinea,39282,+1 869 001-702-453-4851 +78,Miller Ltd,Christopher Harding,16779 Gaines Pines,Port Emilybury,French Polynesia,49688,+1 787 773.486.4294x4654 +79,Gill-Wu,Lauren Wallace,3979 Hernandez Dam,Maldonadoland,Seychelles,94705,+7 7 445-368-2918 +80,Russell Ltd,Adam Wells,6349 Dillon Walks,East Leroy,Netherlands,89085,+27 (511)539-8534x5085 +81,Wright-Liu,Scott Cooley,272 Jason Summit,New Josephmouth,Bolivia,32636,+44 7624 255-335-6363 +82,Johnson LLC,Roger Johnson,745 Howell Square Suite 402,West Sharonbury,Reunion,56963,+359 001-577-254-3040x65663 +83,Roach-Vance,Heather Carter,70512 Jennifer Court Apt. 111,East Ian,Denmark,31831,+500 473.526.3442x778 +84,Zimmerman-Nichols,Steven Adams,53941 Jenkins Squares Apt. 306,Jacksonville,Italy,20728,+61 5355112995 +85,Mills-Lee,Paul Butler,83012 Cameron Alley Suite 465,Alexanderberg,Mauritius,10366,+356 349.304.2204x4442 +86,Williams and Sons,Larry Wolf,567 Bryan Loop,West Douglasville,Hungary,83329,+682 (844)836-0249x3395 +87,"Morse, Gamble and Nielsen",Caleb Martinez,192 Clements Cove Suite 383,Allisonland,Benin,86961,+46 821.455.0676 +88,"Turner, Brown and Humphrey",Bryan Donaldson,46960 Kristy Point,South Richard,Heard Island and McDonald Islands,40299,+30 (336)873-3292 +89,"Jones, Perry and Simpson",Gary Leonard,2750 Smith Rapids,South Vincent,Ethiopia,24732,+222 001-448-765-4306x27651 +90,"Brown, Gutierrez and Trevino",Francisco Reid,1419 Anderson Locks Apt. 916,Charlesview,Uganda,34086,+44 1481 001-679-940-4293x148 +91,Gray and Sons,Walter Cortez,27982 Alex Groves Suite 195,South Chelsea,Belarus,21157,+881 0 +1-540-968-2323 +92,Hall LLC,David Valenzuela,617 Lin Springs,Martinezton,Faroe Islands,71641,+358 001-961-604-6400x66330 +93,"Flores, Day and Thomas",Sarah Bailey,7512 Ricardo Spur Apt. 129,West Wendy,Lesotho,53521,+690 965-950-8716 +94,Mcmahon-Russell,Susan Wilson,6027 White Shoal Apt. 389,North Heathermouth,Norway,59569,+681 6432858874 +95,Pierce LLC,Renee Hamilton,77190 Elizabeth Lights,Lake Michaelburgh,Northern Mariana Islands,74306,+881 6 (991)217-9581x447 +96,Smith Group,James Campbell,683 Alan Drive,East Davidfort,Belarus,65957,+1 264 001-984-480-8124x56878 +97,"Herrera, Griffin and Collins",Colleen Anderson,6755 Jorge Cliffs Suite 040,Robertfort,Christmas Island,81718,+689 9344130980 +98,Fisher and Sons,Brittany Hall,7226 Wells Vista,North Leonardland,Andorra,52421,+46 +1-893-925-6674x565 +99,Martinez LLC,Alexander Moore,51881 Moore Inlet,Crystalfurt,Estonia,59493,+222 (616)864-3066 +100,Pierce-Smith,Sabrina Johnson,8823 Todd Lights Suite 381,Williamsview,Venezuela,22397,+230 +1-382-617-8013x5888 diff --git a/csv/employees.csv b/csv/employees.csv new file mode 100644 index 0000000..13cb08c --- /dev/null +++ b/csv/employees.csv @@ -0,0 +1,21 @@ +employee_id,first_name,last_name,phone +1,Cindy,Wade,+222 656-486-3727 +2,David,Thornton,+882 (369)732-4858x56864 +3,Lauren,Martinez,+250 8878764159 +4,Kenneth,White,+64 4924992211 +5,James,Torres,+267 +1-471-316-0190x308 +6,Tracy,Foster,+237 6225761379 +7,Miranda,Harris,+370 001-563-522-4308x77248 +8,Destiny,Nguyen,+226 284.891.0715 +9,Phillip,Williams,+423 4943292679 +10,Kelli,Bowman,+379 (843)240-1818x77648 +11,Gregory,Pittman,+264 9864625899 +12,Natasha,Hoover,+234 649.763.1540x547 +13,Gregory,Jackson,+243 (871)628-0556 +14,David,Clark,+882 805-740-2877x32513 +15,Sarah,Shepherd,+267 721-710-7210x8468 +16,Michael,Quinn,+972 826.201.6869 +17,Logan,Lopez,+64 +1-264-270-6434 +18,Donald,Hunt,+47 79 (579)967-8837x893 +19,Matthew,Meyers,+378 +1-720-722-2062x240 +20,Thomas,Calderon,+64 +1-380-200-3211 diff --git a/csv/line_items.csv b/csv/line_items.csv new file mode 100644 index 0000000..e1f1d68 --- /dev/null +++ b/csv/line_items.csv @@ -0,0 +1,1110 @@ +line_item_id,order_id,product_id,quantity +1,1,45,6 +2,1,49,20 +3,1,51,11 +4,1,54,17 +5,1,51,7 +6,1,6,2 +7,2,41,6 +8,2,37,5 +9,3,24,16 +10,3,26,18 +11,3,51,5 +12,4,39,18 +13,4,52,20 +14,4,34,16 +15,4,26,6 +16,4,34,14 +17,4,45,19 +18,4,29,14 +19,5,4,14 +20,5,24,9 +21,5,13,1 +22,5,58,11 +23,6,47,11 +24,6,14,7 +25,6,6,9 +26,6,54,15 +27,6,9,12 +28,6,35,14 +29,6,6,6 +30,7,1,18 +31,7,51,1 +32,7,35,1 +33,7,45,3 +34,8,2,5 +35,8,15,5 +36,8,9,16 +37,8,1,7 +38,8,36,7 +39,8,2,16 +40,8,15,19 +41,8,4,12 +42,9,36,14 +43,9,45,14 +44,9,44,16 +45,9,21,13 +46,9,2,9 +47,10,20,12 +48,10,33,8 +49,10,38,19 +50,10,12,1 +51,10,58,16 +52,10,34,19 +53,10,14,5 +54,11,49,19 +55,11,15,11 +56,11,47,16 +57,11,57,11 +58,11,5,5 +59,11,2,14 +60,11,6,18 +61,12,55,18 +62,12,15,10 +63,13,26,9 +64,13,2,1 +65,13,52,4 +66,14,19,5 +67,15,50,20 +68,15,35,17 +69,15,12,5 +70,15,40,13 +71,16,15,14 +72,16,25,10 +73,16,43,7 +74,16,7,7 +75,16,51,3 +76,16,36,3 +77,17,2,17 +78,18,59,15 +79,18,28,12 +80,18,40,4 +81,18,43,20 +82,19,41,13 +83,19,35,5 +84,19,50,16 +85,19,1,1 +86,19,29,5 +87,19,43,3 +88,19,36,11 +89,19,49,18 +90,20,14,5 +91,20,13,7 +92,20,24,10 +93,20,5,6 +94,21,38,14 +95,21,20,5 +96,21,36,5 +97,21,17,14 +98,21,31,17 +99,21,19,7 +100,22,14,14 +101,22,4,9 +102,22,11,13 +103,22,12,11 +104,22,35,16 +105,22,48,9 +106,23,22,8 +107,23,26,14 +108,23,30,1 +109,23,59,4 +110,23,34,8 +111,23,44,7 +112,24,28,1 +113,24,4,14 +114,24,24,3 +115,24,10,4 +116,24,51,10 +117,25,10,4 +118,25,20,14 +119,26,3,2 +120,26,27,18 +121,26,11,8 +122,26,59,3 +123,27,42,15 +124,27,2,19 +125,27,9,14 +126,27,27,16 +127,27,26,14 +128,27,29,16 +129,27,6,5 +130,27,15,16 +131,28,12,10 +132,28,45,20 +133,28,11,17 +134,29,47,14 +135,29,3,14 +136,29,36,5 +137,29,42,10 +138,29,28,10 +139,29,42,15 +140,29,53,19 +141,30,2,11 +142,30,1,17 +143,31,2,14 +144,31,4,13 +145,31,34,16 +146,31,36,9 +147,31,20,6 +148,31,54,2 +149,31,44,13 +150,31,2,17 +151,32,53,7 +152,32,46,3 +153,32,47,3 +154,32,1,1 +155,32,26,1 +156,32,15,15 +157,32,54,20 +158,33,8,14 +159,34,6,2 +160,34,25,5 +161,34,1,11 +162,34,29,3 +163,34,56,7 +164,34,59,16 +165,34,54,8 +166,35,38,20 +167,35,53,19 +168,35,41,12 +169,35,26,19 +170,36,26,20 +171,37,36,12 +172,38,23,5 +173,38,10,10 +174,38,54,4 +175,38,44,2 +176,38,4,13 +177,38,10,13 +178,38,23,1 +179,38,57,11 +180,39,22,19 +181,40,22,10 +182,40,53,20 +183,41,43,14 +184,41,10,19 +185,41,12,20 +186,41,1,2 +187,41,31,10 +188,41,57,2 +189,42,40,8 +190,42,51,5 +191,42,49,12 +192,42,45,19 +193,43,15,12 +194,43,31,9 +195,43,22,13 +196,43,7,7 +197,43,27,6 +198,44,24,11 +199,44,20,6 +200,44,46,17 +201,44,15,9 +202,44,1,11 +203,45,41,10 +204,46,40,9 +205,46,4,5 +206,47,43,6 +207,47,59,18 +208,47,25,4 +209,47,56,18 +210,47,57,13 +211,47,47,20 +212,47,38,15 +213,48,23,19 +214,48,20,16 +215,48,3,20 +216,48,42,16 +217,48,4,7 +218,48,60,1 +219,49,57,14 +220,49,49,17 +221,49,39,6 +222,50,16,10 +223,50,51,2 +224,50,48,7 +225,50,49,20 +226,50,6,3 +227,50,37,18 +228,50,20,9 +229,51,10,12 +230,51,45,18 +231,52,7,16 +232,53,43,9 +233,53,36,16 +234,53,40,15 +235,54,48,16 +236,54,50,8 +237,55,27,11 +238,55,34,20 +239,55,15,16 +240,55,54,5 +241,55,31,11 +242,55,17,6 +243,56,53,5 +244,56,17,11 +245,56,3,12 +246,56,20,17 +247,56,6,13 +248,56,37,19 +249,57,13,14 +250,57,2,1 +251,57,57,8 +252,57,46,13 +253,58,25,10 +254,58,31,3 +255,58,7,18 +256,58,52,5 +257,58,20,5 +258,58,38,19 +259,58,48,18 +260,59,19,9 +261,59,47,20 +262,59,13,4 +263,59,21,20 +264,59,60,9 +265,59,2,2 +266,59,9,8 +267,59,45,17 +268,60,3,12 +269,60,32,3 +270,60,27,7 +271,60,60,1 +272,60,56,12 +273,60,1,5 +274,60,47,12 +275,60,54,2 +276,61,40,1 +277,61,20,9 +278,62,45,10 +279,62,31,7 +280,62,6,2 +281,62,3,1 +282,62,54,12 +283,62,60,19 +284,62,22,4 +285,63,11,18 +286,63,55,1 +287,63,42,10 +288,63,35,8 +289,63,29,12 +290,63,42,9 +291,64,54,9 +292,65,20,2 +293,65,7,20 +294,66,32,3 +295,66,14,14 +296,66,29,7 +297,66,52,13 +298,66,36,15 +299,66,54,20 +300,66,15,7 +301,67,38,15 +302,67,37,11 +303,67,3,9 +304,67,54,14 +305,67,23,20 +306,67,9,17 +307,67,49,20 +308,67,31,4 +309,68,18,18 +310,68,43,11 +311,68,36,6 +312,68,43,14 +313,68,34,20 +314,68,19,20 +315,69,49,18 +316,69,32,13 +317,69,34,10 +318,69,31,4 +319,69,32,18 +320,70,43,1 +321,71,51,17 +322,71,59,11 +323,71,20,18 +324,71,60,10 +325,71,21,10 +326,71,21,6 +327,71,3,1 +328,71,5,9 +329,72,10,1 +330,72,32,3 +331,72,5,20 +332,72,25,11 +333,72,31,11 +334,72,44,19 +335,72,4,11 +336,72,54,2 +337,73,5,1 +338,73,15,11 +339,73,5,17 +340,73,10,12 +341,74,44,8 +342,74,9,10 +343,74,13,12 +344,74,13,3 +345,74,1,19 +346,74,52,15 +347,74,34,5 +348,75,30,19 +349,75,34,12 +350,75,48,20 +351,76,46,10 +352,77,59,15 +353,77,26,17 +354,77,46,8 +355,77,30,9 +356,77,12,12 +357,77,9,15 +358,77,34,5 +359,78,50,9 +360,78,24,5 +361,79,53,15 +362,79,34,13 +363,79,33,7 +364,79,46,14 +365,79,49,12 +366,79,55,6 +367,80,16,15 +368,80,44,16 +369,80,54,14 +370,80,27,8 +371,80,45,16 +372,81,7,7 +373,81,40,18 +374,82,10,17 +375,82,37,13 +376,82,36,20 +377,82,23,7 +378,82,20,6 +379,82,29,10 +380,82,39,2 +381,82,12,19 +382,83,56,5 +383,83,50,17 +384,83,24,13 +385,83,9,11 +386,83,22,12 +387,83,5,13 +388,84,21,11 +389,84,12,6 +390,85,9,18 +391,85,40,12 +392,85,52,14 +393,85,32,15 +394,86,40,5 +395,86,53,1 +396,86,27,1 +397,86,21,3 +398,86,3,2 +399,86,35,11 +400,87,32,3 +401,88,49,19 +402,88,60,19 +403,88,27,14 +404,88,18,1 +405,88,57,1 +406,88,27,20 +407,88,59,9 +408,89,26,11 +409,89,15,4 +410,90,57,8 +411,90,28,5 +412,90,54,20 +413,90,49,11 +414,90,32,20 +415,90,32,12 +416,90,44,7 +417,90,50,18 +418,91,17,19 +419,91,6,2 +420,91,37,19 +421,91,21,6 +422,92,41,10 +423,92,36,12 +424,92,47,6 +425,93,15,8 +426,93,30,13 +427,93,29,12 +428,93,59,3 +429,93,13,11 +430,93,33,13 +431,94,18,6 +432,95,37,17 +433,96,55,17 +434,96,18,17 +435,96,34,1 +436,96,20,1 +437,97,37,7 +438,97,37,17 +439,97,21,5 +440,98,37,4 +441,99,51,17 +442,100,12,19 +443,101,10,18 +444,101,4,6 +445,102,11,3 +446,102,41,5 +447,102,22,9 +448,102,20,18 +449,102,13,9 +450,102,2,8 +451,102,4,7 +452,103,29,12 +453,103,1,4 +454,104,26,14 +455,104,10,14 +456,105,53,9 +457,105,24,11 +458,105,14,6 +459,105,51,20 +460,106,53,8 +461,106,33,4 +462,106,56,17 +463,106,56,4 +464,106,40,9 +465,106,31,10 +466,106,30,1 +467,106,36,20 +468,107,11,16 +469,107,5,16 +470,107,44,20 +471,107,8,13 +472,107,42,2 +473,107,39,20 +474,108,7,17 +475,109,17,20 +476,109,34,14 +477,109,30,16 +478,109,24,16 +479,109,30,14 +480,109,40,11 +481,110,29,19 +482,110,40,3 +483,111,14,5 +484,111,30,4 +485,111,3,17 +486,111,16,2 +487,111,29,3 +488,111,28,6 +489,111,15,7 +490,112,20,12 +491,112,40,8 +492,112,6,10 +493,112,16,1 +494,112,5,17 +495,112,7,7 +496,112,60,17 +497,113,35,18 +498,113,55,3 +499,113,60,9 +500,113,13,15 +501,113,30,1 +502,113,9,16 +503,113,36,13 +504,114,33,5 +505,114,29,11 +506,114,42,15 +507,115,5,6 +508,115,60,1 +509,115,8,10 +510,115,24,2 +511,115,18,3 +512,115,22,11 +513,115,24,5 +514,116,5,1 +515,116,22,12 +516,116,51,8 +517,116,54,14 +518,117,41,17 +519,117,4,12 +520,117,39,16 +521,117,47,6 +522,118,53,2 +523,118,52,2 +524,118,10,2 +525,118,27,12 +526,118,7,14 +527,118,11,6 +528,118,58,20 +529,119,58,10 +530,119,56,16 +531,119,19,17 +532,119,11,13 +533,119,28,6 +534,119,8,10 +535,120,28,16 +536,120,15,8 +537,120,33,5 +538,120,26,7 +539,120,21,14 +540,121,6,8 +541,121,9,1 +542,122,35,18 +543,122,3,7 +544,122,48,14 +545,123,22,13 +546,123,10,7 +547,123,29,11 +548,124,25,1 +549,124,22,9 +550,124,7,8 +551,124,10,4 +552,124,52,15 +553,125,53,20 +554,125,58,14 +555,125,4,13 +556,125,46,11 +557,125,17,2 +558,126,25,13 +559,126,11,14 +560,126,56,16 +561,126,50,20 +562,126,17,14 +563,127,38,9 +564,127,31,12 +565,127,46,3 +566,127,11,11 +567,128,47,15 +568,128,42,19 +569,128,25,13 +570,128,25,17 +571,128,36,2 +572,128,55,18 +573,128,16,15 +574,129,37,5 +575,129,25,3 +576,129,56,16 +577,129,60,19 +578,129,55,18 +579,129,26,14 +580,129,1,20 +581,129,11,11 +582,130,8,8 +583,130,44,20 +584,130,2,14 +585,131,34,5 +586,131,43,1 +587,131,27,9 +588,132,37,1 +589,132,39,7 +590,132,10,20 +591,133,48,16 +592,133,15,10 +593,133,2,13 +594,133,57,13 +595,134,40,4 +596,134,2,19 +597,135,5,13 +598,135,48,19 +599,135,53,14 +600,135,2,14 +601,135,31,7 +602,135,11,10 +603,135,13,16 +604,135,49,15 +605,136,32,11 +606,137,22,5 +607,137,9,14 +608,137,60,17 +609,137,15,9 +610,137,27,15 +611,137,58,15 +612,137,27,7 +613,137,6,2 +614,138,3,16 +615,138,2,15 +616,138,9,10 +617,139,57,15 +618,139,26,16 +619,139,41,15 +620,139,18,11 +621,139,44,9 +622,140,49,1 +623,140,32,19 +624,140,18,13 +625,140,24,17 +626,141,52,3 +627,141,11,15 +628,141,53,11 +629,142,38,16 +630,142,17,9 +631,142,46,12 +632,142,25,8 +633,142,56,8 +634,142,22,8 +635,142,24,6 +636,143,55,17 +637,144,6,16 +638,145,41,2 +639,145,32,15 +640,145,23,17 +641,145,21,14 +642,145,29,11 +643,145,11,20 +644,145,9,11 +645,146,23,4 +646,146,52,13 +647,146,32,4 +648,146,55,9 +649,146,19,19 +650,147,21,10 +651,147,40,15 +652,147,10,2 +653,148,1,10 +654,148,21,11 +655,149,41,6 +656,150,32,13 +657,150,33,10 +658,150,57,12 +659,150,3,11 +660,150,8,20 +661,150,1,13 +662,150,28,13 +663,150,57,19 +664,151,53,14 +665,151,58,14 +666,151,48,14 +667,152,44,19 +668,152,12,3 +669,152,48,6 +670,152,55,17 +671,152,15,5 +672,153,15,6 +673,153,13,12 +674,153,44,4 +675,153,15,6 +676,154,25,18 +677,154,60,9 +678,154,31,15 +679,154,45,12 +680,154,52,19 +681,154,20,18 +682,154,41,18 +683,155,6,9 +684,155,41,10 +685,155,25,9 +686,155,17,4 +687,155,16,12 +688,155,52,11 +689,155,6,19 +690,155,51,1 +691,156,18,4 +692,156,29,7 +693,156,2,18 +694,156,30,1 +695,156,53,20 +696,156,48,8 +697,157,6,10 +698,157,13,16 +699,157,50,7 +700,157,3,5 +701,157,33,17 +702,157,37,6 +703,158,52,15 +704,158,38,5 +705,158,24,15 +706,159,47,14 +707,159,51,9 +708,160,20,18 +709,160,4,4 +710,160,11,4 +711,160,54,20 +712,160,15,11 +713,160,19,13 +714,160,17,11 +715,161,17,14 +716,162,5,14 +717,162,4,13 +718,162,41,5 +719,162,55,18 +720,162,58,18 +721,163,50,15 +722,163,3,5 +723,163,17,1 +724,163,55,19 +725,163,3,20 +726,163,52,5 +727,163,45,4 +728,163,19,6 +729,164,13,17 +730,165,55,4 +731,165,58,8 +732,165,3,7 +733,166,22,3 +734,166,31,6 +735,166,30,10 +736,166,10,18 +737,166,45,2 +738,166,56,14 +739,166,51,7 +740,167,42,3 +741,167,57,3 +742,167,40,9 +743,168,9,19 +744,168,19,4 +745,168,50,11 +746,168,15,11 +747,168,9,11 +748,169,48,11 +749,169,60,1 +750,170,6,11 +751,170,19,16 +752,170,39,11 +753,170,31,9 +754,170,56,3 +755,170,26,17 +756,171,3,19 +757,171,24,4 +758,171,57,12 +759,171,13,2 +760,171,31,16 +761,171,11,15 +762,171,24,12 +763,171,49,15 +764,172,8,11 +765,172,36,17 +766,172,37,8 +767,172,9,11 +768,173,22,10 +769,173,23,19 +770,173,14,15 +771,173,4,13 +772,173,46,13 +773,173,14,16 +774,173,52,20 +775,173,31,10 +776,174,32,1 +777,175,12,20 +778,176,39,11 +779,176,31,14 +780,176,18,8 +781,177,40,9 +782,178,24,8 +783,178,37,7 +784,178,60,17 +785,179,20,17 +786,179,48,11 +787,180,29,18 +788,180,27,13 +789,180,4,15 +790,181,10,5 +791,181,10,6 +792,181,58,5 +793,181,1,17 +794,181,51,11 +795,181,19,8 +796,181,17,1 +797,181,13,11 +798,182,45,7 +799,182,7,20 +800,182,6,12 +801,182,34,18 +802,182,38,14 +803,182,19,15 +804,182,17,14 +805,182,56,18 +806,183,10,4 +807,183,26,15 +808,183,27,1 +809,183,12,9 +810,184,1,3 +811,184,35,13 +812,184,52,19 +813,184,25,16 +814,184,32,20 +815,184,39,19 +816,184,42,8 +817,184,21,7 +818,185,46,2 +819,185,58,18 +820,185,45,5 +821,185,49,13 +822,185,11,6 +823,185,44,8 +824,186,58,1 +825,186,9,3 +826,187,11,14 +827,187,42,2 +828,187,27,3 +829,187,57,11 +830,187,43,8 +831,187,14,18 +832,187,37,19 +833,188,18,5 +834,188,5,16 +835,188,55,3 +836,188,9,14 +837,189,40,12 +838,190,40,8 +839,190,45,3 +840,190,11,17 +841,190,51,14 +842,190,53,14 +843,190,39,16 +844,191,59,15 +845,191,35,18 +846,192,12,6 +847,193,52,11 +848,193,7,14 +849,193,58,5 +850,193,43,6 +851,193,12,19 +852,193,20,9 +853,194,21,12 +854,194,38,4 +855,194,37,9 +856,194,57,3 +857,195,59,20 +858,195,33,16 +859,196,19,7 +860,196,4,17 +861,196,39,4 +862,196,46,14 +863,196,10,7 +864,196,26,9 +865,197,52,7 +866,197,9,15 +867,197,28,12 +868,197,6,14 +869,197,11,6 +870,197,10,20 +871,197,6,20 +872,198,18,3 +873,198,43,13 +874,198,26,16 +875,198,25,4 +876,198,12,1 +877,198,1,9 +878,199,38,1 +879,199,42,12 +880,199,55,9 +881,200,1,13 +882,200,50,7 +883,200,40,20 +884,200,1,20 +885,200,14,3 +886,201,44,12 +887,201,12,9 +888,201,26,2 +889,202,24,15 +890,202,25,3 +891,202,32,5 +892,202,59,8 +893,202,33,14 +894,203,54,16 +895,203,14,15 +896,203,44,18 +897,203,29,11 +898,203,51,19 +899,203,44,15 +900,203,19,6 +901,203,52,12 +902,204,37,19 +903,204,2,10 +904,204,13,6 +905,204,57,7 +906,204,58,13 +907,204,26,6 +908,205,6,11 +909,205,30,13 +910,206,14,13 +911,206,28,2 +912,206,38,2 +913,206,45,3 +914,206,36,16 +915,207,29,17 +916,207,16,20 +917,207,10,13 +918,207,53,10 +919,208,2,18 +920,208,60,14 +921,208,39,7 +922,208,54,20 +923,208,12,15 +924,208,5,8 +925,208,14,13 +926,208,16,20 +927,209,7,10 +928,210,17,19 +929,210,25,15 +930,210,14,14 +931,210,50,19 +932,210,26,20 +933,210,8,1 +934,210,25,19 +935,211,53,1 +936,211,50,16 +937,211,5,20 +938,212,15,3 +939,212,49,16 +940,212,4,6 +941,213,13,11 +942,213,2,6 +943,213,55,9 +944,213,37,13 +945,213,55,7 +946,213,35,11 +947,214,8,6 +948,214,29,18 +949,215,11,15 +950,215,7,18 +951,215,38,5 +952,215,43,20 +953,215,21,7 +954,215,35,11 +955,215,21,17 +956,215,55,15 +957,216,23,10 +958,216,28,12 +959,217,54,19 +960,217,12,16 +961,217,18,9 +962,217,15,11 +963,217,10,15 +964,217,30,8 +965,218,10,20 +966,219,31,3 +967,219,13,10 +968,219,50,15 +969,219,19,8 +970,220,24,2 +971,220,26,16 +972,220,9,5 +973,220,15,13 +974,221,39,19 +975,221,58,10 +976,221,37,17 +977,221,1,6 +978,221,38,3 +979,222,27,9 +980,222,19,19 +981,222,9,4 +982,222,5,7 +983,222,10,11 +984,222,53,20 +985,223,10,4 +986,223,7,5 +987,223,6,12 +988,223,7,18 +989,223,15,16 +990,223,3,2 +991,224,23,13 +992,224,48,12 +993,224,57,1 +994,225,31,7 +995,226,17,7 +996,226,14,4 +997,226,23,20 +998,226,57,1 +999,226,17,3 +1000,226,4,20 +1001,226,60,11 +1002,227,20,13 +1003,227,11,1 +1004,227,5,3 +1005,228,8,7 +1006,228,26,11 +1007,228,48,9 +1008,228,59,12 +1009,228,21,20 +1010,229,25,8 +1011,229,24,15 +1012,229,22,9 +1013,229,34,6 +1014,229,2,9 +1015,229,59,15 +1016,229,28,16 +1017,230,17,10 +1018,230,16,2 +1019,230,31,5 +1020,230,31,19 +1021,231,58,12 +1022,231,53,15 +1023,231,5,17 +1024,231,2,19 +1025,231,38,7 +1026,231,45,13 +1027,232,8,13 +1028,232,45,1 +1029,232,38,13 +1030,232,20,19 +1031,232,15,20 +1032,233,44,11 +1033,233,50,15 +1034,233,29,4 +1035,233,60,9 +1036,233,56,4 +1037,233,10,17 +1038,234,30,18 +1039,234,2,19 +1040,234,16,19 +1041,234,41,2 +1042,234,32,20 +1043,234,48,1 +1044,235,31,4 +1045,235,13,18 +1046,235,14,18 +1047,235,40,2 +1048,235,19,14 +1049,236,11,13 +1050,236,36,11 +1051,236,32,7 +1052,236,42,12 +1053,236,34,20 +1054,236,56,1 +1055,236,22,2 +1056,236,56,7 +1057,237,26,3 +1058,237,25,10 +1059,238,2,10 +1060,238,50,14 +1061,238,36,2 +1062,238,55,18 +1063,238,47,4 +1064,238,14,4 +1065,239,10,11 +1066,239,46,9 +1067,239,43,12 +1068,239,38,8 +1069,239,18,12 +1070,239,7,20 +1071,239,45,10 +1072,239,6,16 +1073,240,17,1 +1074,240,50,5 +1075,240,29,18 +1076,240,49,6 +1077,240,37,12 +1078,240,21,10 +1079,240,36,8 +1080,241,12,9 +1081,241,45,4 +1082,241,1,18 +1083,241,47,17 +1084,242,58,5 +1085,242,8,15 +1086,242,6,9 +1087,243,2,19 +1088,243,15,18 +1089,243,53,12 +1090,243,10,20 +1091,243,34,6 +1092,243,50,11 +1093,244,35,6 +1094,244,45,14 +1095,244,57,4 +1096,244,54,1 +1097,244,16,3 +1098,244,4,5 +1099,245,16,4 +1100,246,46,18 +1101,246,7,3 +1102,246,15,16 +1103,246,23,3 +1104,246,5,6 +1105,247,35,18 +1106,247,14,14 +1107,248,2,6 +1108,249,6,19 +1109,249,46,1 diff --git a/csv/orders.csv b/csv/orders.csv new file mode 100644 index 0000000..c42c629 --- /dev/null +++ b/csv/orders.csv @@ -0,0 +1,250 @@ +order_id,date,customer_id,employee_id +1,1970-06-10,45,11 +2,1970-06-28,7,2 +3,1970-10-28,34,5 +4,1970-11-03,36,20 +5,1971-03-14,27,14 +6,1971-07-28,27,14 +7,1971-08-04,71,5 +8,1971-10-21,73,11 +9,1971-12-28,96,16 +10,1972-04-04,45,16 +11,1972-06-23,51,13 +12,1972-07-17,81,19 +13,1973-01-21,95,17 +14,1973-02-14,72,10 +15,1973-12-09,55,17 +16,1973-12-14,58,8 +17,1974-01-08,66,7 +18,1974-03-18,31,18 +19,1974-03-25,70,19 +20,1974-05-25,72,12 +21,1974-06-25,93,1 +22,1974-08-24,81,2 +23,1974-09-21,86,11 +24,1975-01-12,16,16 +25,1975-02-05,43,8 +26,1975-02-09,30,7 +27,1975-02-18,41,19 +28,1975-03-24,48,13 +29,1975-04-07,85,14 +30,1975-06-20,32,1 +31,1975-07-10,39,15 +32,1976-04-03,63,12 +33,1976-10-01,56,3 +34,1977-06-19,46,17 +35,1977-08-18,49,8 +36,1978-04-22,36,19 +37,1978-05-11,62,18 +38,1978-05-31,94,17 +39,1979-02-20,48,16 +40,1979-09-07,97,1 +41,1979-10-02,100,11 +42,1979-11-27,79,18 +43,1979-12-01,13,1 +44,1980-04-01,9,1 +45,1980-04-03,45,1 +46,1980-06-01,47,10 +47,1980-07-18,97,9 +48,1980-08-01,76,17 +49,1980-09-05,25,7 +50,1980-11-26,32,3 +51,1981-02-25,15,16 +52,1981-04-18,69,9 +53,1981-04-18,64,14 +54,1981-05-16,8,3 +55,1981-06-27,62,4 +56,1981-08-18,38,19 +57,1981-12-13,35,15 +58,1982-01-01,65,9 +59,1982-01-03,87,15 +60,1982-07-23,13,19 +61,1982-07-24,29,5 +62,1982-09-04,39,5 +63,1983-05-22,2,17 +64,1983-06-14,92,11 +65,1983-10-27,18,6 +66,1984-04-24,19,15 +67,1984-07-15,50,2 +68,1984-12-05,68,13 +69,1986-04-05,45,10 +70,1986-06-03,34,3 +71,1986-06-06,11,13 +72,1986-06-27,23,19 +73,1986-11-14,16,10 +74,1986-12-25,74,9 +75,1987-01-03,21,2 +76,1987-01-22,34,4 +77,1987-02-23,85,19 +78,1987-03-28,48,6 +79,1987-06-18,46,6 +80,1987-11-02,89,13 +81,1988-09-11,100,6 +82,1988-12-26,10,20 +83,1989-10-21,49,5 +84,1990-04-30,19,1 +85,1990-07-08,92,18 +86,1990-08-07,61,19 +87,1990-12-13,51,19 +88,1991-08-09,47,7 +89,1991-08-23,38,8 +90,1992-04-10,77,20 +91,1992-04-28,42,9 +92,1992-10-16,67,11 +93,1992-12-19,25,12 +94,1992-12-23,27,10 +95,1993-01-15,62,5 +96,1993-03-13,54,6 +97,1993-04-14,32,9 +98,1993-04-18,19,9 +99,1993-07-24,3,16 +100,1993-09-23,16,19 +101,1994-07-17,13,10 +102,1994-08-10,44,14 +103,1995-02-22,72,12 +104,1995-02-24,62,7 +105,1995-06-07,44,14 +106,1995-10-03,22,3 +107,1996-03-08,64,11 +108,1996-05-11,81,18 +109,1996-06-01,1,17 +110,1996-10-29,40,7 +111,1997-03-22,52,16 +112,1997-04-04,69,11 +113,1997-10-05,41,17 +114,1997-11-26,40,7 +115,1998-01-09,71,17 +116,1998-05-02,16,17 +117,1998-09-27,34,17 +118,1998-10-12,19,18 +119,1999-03-08,87,9 +120,1999-04-08,6,1 +121,1999-06-16,76,6 +122,1999-06-24,65,20 +123,1999-07-30,48,4 +124,2000-02-25,31,17 +125,2000-06-30,83,9 +126,2001-01-14,55,14 +127,2001-01-18,98,6 +128,2001-03-11,74,5 +129,2001-04-21,86,3 +130,2001-06-12,53,3 +131,2001-06-16,10,1 +132,2001-07-03,32,1 +133,2001-08-12,15,5 +134,2001-10-02,78,8 +135,2001-12-16,76,16 +136,2002-05-02,55,6 +137,2002-09-09,15,3 +138,2003-08-21,64,10 +139,2003-11-28,66,16 +140,2003-12-28,75,3 +141,2004-02-21,46,3 +142,2004-02-23,82,10 +143,2004-08-31,24,20 +144,2004-10-26,43,11 +145,2004-12-30,37,6 +146,2005-06-05,19,14 +147,2005-07-17,5,5 +148,2005-09-11,87,2 +149,2005-09-27,34,11 +150,2006-02-04,80,17 +151,2006-03-11,53,8 +152,2006-07-28,56,5 +153,2006-08-25,41,12 +154,2006-10-18,68,20 +155,2007-01-16,18,4 +156,2007-01-28,63,9 +157,2007-02-22,38,19 +158,2007-03-04,10,8 +159,2007-04-10,53,13 +160,2007-05-15,72,10 +161,2007-06-12,17,10 +162,2007-08-01,66,3 +163,2007-09-19,96,11 +164,2007-12-12,55,10 +165,2008-02-02,58,20 +166,2008-02-12,14,18 +167,2008-05-24,40,6 +168,2008-12-09,93,2 +169,2009-01-14,86,3 +170,2009-02-23,39,15 +171,2009-04-16,47,3 +172,2009-05-19,45,3 +173,2009-07-28,83,7 +174,2010-06-04,40,20 +175,2010-06-23,20,19 +176,2010-09-07,11,12 +177,2010-10-24,51,6 +178,2010-11-07,44,7 +179,2011-01-10,66,1 +180,2011-01-11,53,6 +181,2011-04-18,79,19 +182,2011-04-29,63,15 +183,2011-05-09,17,19 +184,2011-06-04,55,8 +185,2011-08-02,14,5 +186,2011-11-05,8,11 +187,2012-02-24,51,15 +188,2012-03-18,13,12 +189,2012-03-24,59,9 +190,2012-06-10,86,19 +191,2012-10-12,12,4 +192,2013-05-15,31,2 +193,2013-07-24,28,17 +194,2013-08-13,49,11 +195,2014-03-11,56,16 +196,2014-05-31,5,4 +197,2014-09-17,27,15 +198,2014-10-23,45,2 +199,2015-01-21,98,6 +200,2015-05-03,8,13 +201,2015-07-23,59,1 +202,2015-09-09,48,2 +203,2015-11-16,90,11 +204,2016-01-23,51,8 +205,2016-04-15,64,17 +206,2017-01-08,38,19 +207,2017-05-20,11,2 +208,2017-05-30,89,18 +209,2017-08-14,97,20 +210,2017-11-25,14,13 +211,2018-03-14,11,4 +212,2018-09-12,45,4 +213,2018-11-20,87,18 +214,2018-12-06,64,11 +215,2019-02-18,39,7 +216,2019-07-02,19,6 +217,2019-07-28,49,8 +218,2019-09-07,85,7 +219,2019-09-22,98,2 +220,2019-09-25,79,2 +221,2020-01-15,9,15 +222,2020-06-19,55,18 +223,2021-02-17,22,2 +224,2021-04-20,44,14 +225,2021-05-29,7,13 +226,2021-06-05,32,10 +227,2021-06-30,90,11 +228,2021-07-13,54,9 +229,2021-07-30,25,14 +230,2021-10-26,62,18 +231,2021-11-10,34,13 +232,2021-12-03,80,5 +233,2022-01-19,17,18 +234,2022-06-03,89,10 +235,2022-06-10,23,20 +236,2022-07-26,72,14 +237,2022-08-10,57,16 +238,2022-09-18,1,17 +239,2022-10-22,88,10 +240,2023-01-12,1,9 +241,2023-02-22,47,13 +242,2023-04-19,19,12 +243,2023-06-05,92,16 +244,2023-07-19,19,20 +245,2023-08-12,90,19 +246,2023-08-21,73,7 +247,2023-11-21,96,13 +248,2024-04-27,7,8 +249,2024-07-21,81,12 diff --git a/csv/products.csv b/csv/products.csv new file mode 100644 index 0000000..0d65a3d --- /dev/null +++ b/csv/products.csv @@ -0,0 +1,60 @@ +product_id,product_name,price +1,Fantastic Shoes,2.25 +2,For repair Soft Table,5.19 +3,Sausages,5.42 +4,Ergonomic Wooden Soap,8.99 +5,Wooden Shoes,8.22 +6,Cotton Bike,8.34 +7,Sleek Granite Car,9.03 +8,Concrete Cheese,1.46 +9,Unbranded Wooden Keyboard,0.83 +10,Cotton Sausages,9.89 +11,Shoes,7.13 +12,Mouse,6.42 +13,Soft Pizza,1.81 +14,Handcrafted Hat,3.55 +15,Small Fish,1.34 +16,Gorgeous Salad,9.85 +17,Fantastic Sausages,8.1 +18,Shirt,0.23 +19,Hat,6.92 +20,Licensed Cheese,3.93 +21,Steel Car,9.18 +22,Small Shirt,6.81 +23,Bike,0.12 +24,Plastic Pants,6.62 +25,Incredible Hat,1.92 +26,Unbranded Chicken,4.86 +27,Table,2.67 +28,Concrete Gloves,5.71 +29,For repair Fresh Fish,9.26 +30,Refined Cotton Sausages,3.78 +31,Steel Mouse,1.24 +32,Tasty Pizza,4.15 +33,Steel Computer,7.42 +34,Concrete Pants,8.52 +35,Practical Fish,8.83 +36,Sleek Concrete Cheese,3.92 +37,Frozen Computer,2.26 +38,Wooden Mouse,5.04 +39,Unbranded Wooden Hat,6.36 +40,Cotton Ball,6.59 +41,Practical Steel Towels,4.49 +42,Mouse,9.46 +43,Salad,0.53 +44,Practical Tuna,1.0 +45,Handcrafted Wooden Fish,8.95 +46,Sausages,3.79 +47,Tuna,9.72 +48,Rubber Mouse,7.85 +49,Steel Sausages,5.35 +50,Fantastic Fish,9.59 +51,Pants,9.89 +52,Rubber Towels,4.72 +53,Ergonomic Cheese,5.01 +54,Licensed Plastic Bike,9.3 +55,Chair,3.62 +56,Refined Ball,6.3 +57,New Fresh Chips,7.73 +58,Intelligent Chips,7.69 +59,Ball,8.45 diff --git a/db/.gitignore b/db/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/db/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/load_db.py b/load_db.py new file mode 100644 index 0000000..a75941d --- /dev/null +++ b/load_db.py @@ -0,0 +1,77 @@ +import pandas as pd +import sqlalchemy as sa +import sqlite3 +import os +db_path = "./db/lesson.db" + +if os.path.exists(db_path): + answer = input("The database exists. Do you want to recreate it (y/n)?") + if answer.lower() != 'y': + exit(0) + os.remove(db_path) + +with sqlite3.connect("./db/lesson.db",isolation_level='IMMEDIATE') as conn: + conn = sqlite3.connect("./db/lesson.db",isolation_level='IMMEDIATE') + conn.execute("PRAGMA foreign_keys = 1") + cursor = conn.cursor() + # customer_name,contact,street,city,country,postal_code,phone + # Create tables + cursor.execute(""" + CREATE TABLE IF NOT EXISTS customers ( + customer_id INTEGER PRIMARY KEY, + customer_name TEXT, + contact TEXT, + street TEXT, + city TEXT, + postal_code TEXT, + country TEXT, + phone TEXT + ) + """) + cursor.execute(""" + CREATE TABLE IF NOT EXISTS employees ( + employee_id INTEGER PRIMARY KEY, + first_name TEXT, + last_name TEXT, + phone TEXT + ) + """) + cursor.execute(""" + CREATE TABLE IF NOT EXISTS products ( + product_id INTEGER PRIMARY KEY, + product_name TEXT, + price REAL + ) + """) + cursor.execute(""" + CREATE TABLE IF NOT EXISTS line_items ( + line_item_id INTEGER PRIMARY KEY, + order_id INTEGER, + product_id INTEGER, + quantity INTEGER, + FOREIGN KEY(order_id) REFERENCES orders(order_id), + FOREIGN KEY(product_id) REFERENCES products(product_id) + ) + """) + cursor.execute(""" + CREATE TABLE IF NOT EXISTS orders ( + order_id INTEGER PRIMARY KEY, + customer_id INTEGER, + employee_id INTEGER, + date TEXT, + FOREIGN KEY(customer_id) REFERENCES customers(customer_id), + FOREIGN KEY(employee_id) REFERENCES employees(employee_id) + ) + """) + +# Create a database engine +engine = sa.create_engine('sqlite:///db/lesson.db') + +tables = ["customers", "employees", + "products", "orders", "line_items"] + +for table in tables: + t_name = table.lower() + csv_file = "./csv/" + table + ".csv" + data = pd.read_csv(csv_file, sep=',') + data.to_sql(t_name, engine, if_exists='append', index=False) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5390e16 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +pytest==8.1.1 +pandas==2.2.3 +sqlalchemy==2.0.36 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +nbstripout==0.8.1 \ No newline at end of file diff --git a/requirements_dev.txt b/requirements_dev.txt deleted file mode 100644 index 55b033e..0000000 --- a/requirements_dev.txt +++ /dev/null @@ -1 +0,0 @@ -pytest \ No newline at end of file diff --git a/sqlcommand.py b/sqlcommand.py new file mode 100644 index 0000000..f9fa419 --- /dev/null +++ b/sqlcommand.py @@ -0,0 +1,68 @@ +import readline # Provides command line editing and history +import sqlite3 # For SQL command execution +import sys +conn = sqlite3.connect("./db/lesson.db",isolation_level='IMMEDIATE') +conn.execute("PRAGMA foreign_keys = 1") + +cursor = conn.cursor() + + +tables = cursor.execute("SELECT name FROM sqlite_schema WHERE type='table' ORDER BY 'name'").fetchall() +print("The tables in this database are:") +for row in tables: + print(row[0]) +print("Enter SQL statements below, ending with a semicolon. Or, type exit to quit.") + +def main(): + # Connect to an in-memory SQLite database (or replace with a file database) + + # Initialize command history and command input buffer + command_buffer = [] + print("Welcome to the SQL shell! Type 'exit;' to quit.") + + while True: + try: + # Prompt depending on whether we're in the middle of a command + prompt = "sql> " if not command_buffer else " -> " + line = input(prompt) + + # Check for exit command + if line.strip().lower() == "exit;": + print("Exiting.") + break + + # Add line to the command buffer + command_buffer.append(line) + + # If line ends with a semicolon, it's the end of a command + if line.strip().endswith(";"): + # Join all lines in the buffer into a single command + full_command = " ".join(command_buffer).strip() + + # Clear the buffer + command_buffer = [] + + # Execute the command and handle any SQL exceptions + try: + cursor.execute(full_command) + results = cursor.fetchall() + for row in results: + print(row) + except sqlite3.Error as e: + print(f"SQL Error: {e}") + + # Commit changes if it’s an INSERT, UPDATE, or DELETE + conn.commit() + + except EOFError: # Handle Ctrl-D (EOF) gracefully + print("\nExiting.") + break + except KeyboardInterrupt: # Handle Ctrl-C (interrupt) + print("\nCommand canceled.") + command_buffer = [] # Reset the command buffer + + # Clean up the database connection + conn.close() + +if __name__ == "__main__": + main() From 59dcdfefe2916645b675a4da6fab26bba422cc3e Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Thu, 30 Jan 2025 19:51:42 -0500 Subject: [PATCH 03/27] add reference to Git Bash --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f84e27..e536faf 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ python -m venv .venv source .venv/bin/activate code . ``` -For some environments, you have to use the `python3` command. For Windows users, the command is different: +For some environments, you have to use the `python3` command. For Windows users (you should use Git Bash in Windows), the command is different: ```shell python -m venv .venv source .venv/Scripts/activate From a275328d6dbcf3b7c75b5892d152466b3753d609 Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Sat, 1 Feb 2025 11:40:09 -0500 Subject: [PATCH 04/27] add example assignment 8 solution --- examples/advanced_sql.py | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 examples/advanced_sql.py diff --git a/examples/advanced_sql.py b/examples/advanced_sql.py new file mode 100644 index 0000000..e068606 --- /dev/null +++ b/examples/advanced_sql.py @@ -0,0 +1,74 @@ +import sqlite3 + +try: # SQL operations can raise exceptions! + + # The with statement is helpful, because it ensures that the connection + # is closed at the end, even if an exception occurs + with sqlite3.connect("./db/lesson.db",isolation_level='IMMEDIATE') as conn: + cursor = conn.cursor() + # This does a SELECT and a subquery + stmt = """SELECT o.order_id, l.line_item_id, p.product_name FROM orders + o JOIN line_items l on o.order_id = l.order_id JOIN products p on + l.product_id = p.product_id WHERE o.order_id IN + (SELECT order_id from orders ORDER BY order_id limit 5);""" + cursor.execute(stmt) + result = cursor.fetchall() + for row in result: + print(row) + + # This retrieves the first 5 orders joined with the line_items and products tables, + # and aggregates (SUM) the quantity by the price to give the cost of each order + stmt = """SELECT o.order_id, SUM(l.quantity * p.price) FROM orders o JOIN line_items l ON + o.order_id = l.order_id JOIN products p on l.product_id = p.product_id GROUP BY o.order_id + ORDER BY o.order_id LIMIT 5;""" + cursor.execute(stmt) + result = cursor.fetchall() + for row in result: + print(row) + + # This creates a new order with corresponding line_items. First, we get the ids of + # the customer, the employee, and the products. + stmt = """SELECT customer_id FROM customers WHERE customer_name = \"Perez and Sons\";""" + cursor.execute(stmt) + result = cursor.fetchone() + print(result) + customer_id = result[0] + stmt = """SELECT employee_id FROM employees WHERE first_name = \"Miranda\" AND last_name = \"Harris\";""" + cursor.execute(stmt) + result = cursor.fetchone() + print(result) + employee_id = result[0] + stmt = """SELECT product_id FROM products ORDER BY price DESC LIMIT 5""" + cursor.execute(stmt) + result=cursor.fetchall() + print(result) + products = result + + # Now we add the order, saving the returned order_id. This example uses a parameterized + # statement. It is not really necessary to use a parameterized statement when the + # values come from a trusted source, because no SQL injection could occur in that case. + stmt = f"""INSERT INTO orders (employee_id, customer_id) VALUES (?,?) RETURNING order_id""" + cursor.execute(stmt,(employee_id, customer_id)) + result = cursor.fetchone() + print(result) + order_id = result[0] + values = [] + for i in range(5): + values.append(f"({order_id}, {products[i][0]}, 10)") + values_string = ",".join(values) + + stmt = f"""INSERT INTO line_items (order_id, product_id, quantity) VALUES {values_string};""" + print(stmt) + cursor.execute(stmt) + conn.commit() + stmt=f"""SELECT l.line_item_id, l.quantity, p.product_name FROM line_items l JOIN products p ON + l.product_id = p.product_id WHERE l.order_id = {order_id};""" + cursor.execute(stmt) + result = cursor.fetchall() + for row in result: + print(row) +except Exception as e: + print(f"An exception occurred: {e}") +else: + print("All SQL operations completed.") + \ No newline at end of file From 876fd7e482bbe409dae1ed2ce851efe5778db79b Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Sat, 1 Feb 2025 12:57:36 -0500 Subject: [PATCH 05/27] add foreign key constraint to example --- examples/advanced_sql.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/advanced_sql.py b/examples/advanced_sql.py index e068606..ea77e40 100644 --- a/examples/advanced_sql.py +++ b/examples/advanced_sql.py @@ -6,6 +6,7 @@ # is closed at the end, even if an exception occurs with sqlite3.connect("./db/lesson.db",isolation_level='IMMEDIATE') as conn: cursor = conn.cursor() + conn.execute("PRAGMA foreign_keys = 1") # This does a SELECT and a subquery stmt = """SELECT o.order_id, l.line_item_id, p.product_name FROM orders o JOIN line_items l on o.order_id = l.order_id JOIN products p on From ae4e178fa1cc2394d698cad55575df00258aaa3f Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Fri, 7 Feb 2025 00:35:45 -0500 Subject: [PATCH 06/27] add pytest and sample solution for assignment1 --- assignment1/assignment1-test.py | 59 +++++++++++++ assignment1/assignment1.py | 1 + examples/assignment1.py | 144 ++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 assignment1/assignment1-test.py create mode 100644 assignment1/assignment1.py create mode 100644 examples/assignment1.py diff --git a/assignment1/assignment1-test.py b/assignment1/assignment1-test.py new file mode 100644 index 0000000..9333a2e --- /dev/null +++ b/assignment1/assignment1-test.py @@ -0,0 +1,59 @@ +import assignment1 as a1 + +def test_hello(): + assert a1.hello() == "Hello!" + +def test_greet(): + assert a1.greet("James") == "Hello, James!" + +def test_calc(): + assert a1.calc(5,6) == 30 + assert a1.calc(5,6,"add") == 11 + assert a1.calc(20,5,"divide") == 4 + assert a1.calc(14,2.0,"multiply") == 28.0 + assert a1.calc(12.6, 4.4, "subtract") == 8.2 + assert a1.calc(9,5, "modulo") == 4 + assert a1.calc(10,0,"divide") == "You can't divide by 0!" + assert a1.calc("first", "second", "multiply") == "You can't multiply those values!" + +def test_data_type_conversion(): + result = a1.data_type_conversion("110", "int") + assert type(result).__name__ == "int" + assert result == 110 + result = a1.data_type_conversion("5.5", "float") + assert type(result).__name__ == "float" + assert result == 5.5 + result = a1.data_type_conversion(7,"float") + assert type(result).__name__ == "float" + assert result == 7.0 + result = a1.data_type_conversion(91.1,"str") + assert type(result).__name__ == "str" + assert result == "91.1" + assert a1.data_type_conversion("banana", "int") == "You can't convert banana into a int." + +def test_grade(): + assert a1.grade(75,85,95) == "B" + assert a1.grade("three", "blind", "mice") == "Invalid data was provided." + +def test_repeat(): + assert a1.repeat("up,", 4) == "up,up,up,up," + +def test_student_scores(): + assert a1.student_scores("mean", Tom=75, Dick=89, Angela=91) == (75 + 89 + 91) / 3 + assert a1.student_scores("best", Tom=75, Dick=89, Angela=91, Frank=50 ) == "Angela" + +def test_titleize(): + assert a1.titleize("war and peace") == "War and Peace" + assert a1.titleize("a separate peace") == "A Separate Peace" + assert a1.titleize("after on") == "After On" + +def test_hangman(): + assert a1.hangman("difficulty","ic") == "_i__ic____" + +def test_pig_latin(): + assert a1.pig_latin("apple") == "appleay" + assert a1.pig_latin("banana") == "ananabay" + assert a1.pig_latin("cherry") == "errychay" + assert a1.pig_latin("quiet") == "ietquay" + assert a1.pig_latin("square") == "aresquay" + assert a1.pig_latin("the quick brown fox") == "ethay ickquay ownbray oxfay" \ No newline at end of file diff --git a/assignment1/assignment1.py b/assignment1/assignment1.py new file mode 100644 index 0000000..fafa187 --- /dev/null +++ b/assignment1/assignment1.py @@ -0,0 +1 @@ +# Write your code here. \ No newline at end of file diff --git a/examples/assignment1.py b/examples/assignment1.py new file mode 100644 index 0000000..110fcaa --- /dev/null +++ b/examples/assignment1.py @@ -0,0 +1,144 @@ +# Write your code here. +def hello(): + return "Hello!" + +print("hello: ", hello()) + +def greet(name): + return f"Hello, {name}!" + +print("greet: ", greet("Fred")) + +def calc(v1, v2, op="multiply"): + try: + match op: + case "multiply": + return v1 * v2 + case "add": + return v1 + v2 + case "subtract": + return v1 - v2 + case "divide": + return v1 / v2 + case "power": + return v1 ** v2 + case "modulo": + return v1 % v2 + case "int_divide": + return v1 // v2 + case _: + return "unsupported operation" + except ZeroDivisionError: + return "You can't divide by 0!" + except TypeError: + return f"You can't {op} those values!" + +print("calc: ", calc(7,8,"add")) + +def data_type_conversion(value, type_name): + try: + match type_name: + case "int": + return int(value) + case "float": + return float(value) + case "str": + return str(value) + except ValueError: + return f"You can't convert {value} into a {type_name}." + +print("data_type_conversion: ", data_type_conversion(5.23, "int")) + +def grade(*args): + try: + avg = sum(args) / len(args) + if avg >= 90: + return "A" + elif avg >= 80: + return "B" + elif avg >= 70: + return "C" + elif avg >= 60: + return "D" + else: + return "F" + except TypeError: + return "Invalid data was provided." + +print("grade: ", grade(90,79, 95, 80)) + +def repeat(string, count): + out_string = string + for i in range(1,count): + out_string += string + return out_string + +print("repeat: ", repeat("good ",3)) + +def student_scores(operation, **kwargs): + if operation == "best": + best_value = 0 + for key, value in kwargs.items(): + if value > best_value: + best_name = key + best_value = value + return best_name + else: + return sum(kwargs.values()) / len(kwargs.values()) + +print("student_scores: ", student_scores("best", Bob=70, Susan=90)) + +def titleize(title): + title_list = title.split() + little_words = ["a", "on", "an", "the", "of", "and", "is", "in"] + for i, word in enumerate(title_list): + if word not in little_words: + title_list[i] = word.capitalize() + title_list[0] = title_list[0].capitalize() + title_list[-1] = title_list[-1].capitalize() + return " ".join(title_list) + +print("titleize: ", titleize("dancing at the rascal fair")) + +def hangman(secret, guess): + report = "" + for c in secret: + if c in guess: + report += c + else: + report += "_" + return report + +print("hangman: ", hangman("obscurely", "bur")) + +def pig_latin(s): + vowels = "aeiouAEIOU" + out_string = "" + start_string = "" + rest_string = "" + for ch in s: + if (ch == " "): + if (rest_string): + if len(out_string) > 0: + out_string += " " + out_string += rest_string + start_string + "ay" + rest_string = "" + start_string = "" + elif len(rest_string) > 0: + rest_string += ch + elif (ch == "u" or ch == "U") and len(start_string) > 0 and \ + (start_string[-1] == "q" or start_string[-1] == "Q"): + start_string += ch + elif ch in vowels: + rest_string += ch + elif len(rest_string) > 0: + rest_string += ch + else: + start_string += ch + if len(rest_string) > 0: + if len(out_string) > 0: + out_string += " " + out_string += rest_string + start_string + "ay" + return out_string + +print("pig_latin: ", pig_latin("it is forbidden to spit on cats")) From df510e100fad36e210a70186317b97dcc072bef5 Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Sat, 8 Feb 2025 23:00:08 -0500 Subject: [PATCH 07/27] add folder and test script for assignment 2 --- assignment2/assignment2-test.py | 41 +++++++++++++++++++++ examples/assignment2.py | 65 +++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 assignment2/assignment2-test.py create mode 100644 examples/assignment2.py diff --git a/assignment2/assignment2-test.py b/assignment2/assignment2-test.py new file mode 100644 index 0000000..87dd90b --- /dev/null +++ b/assignment2/assignment2-test.py @@ -0,0 +1,41 @@ +import assignment2 as a2 + +def test_read_employees(): + employees = a2.read_employees() + assert employees != None + assert a2.employees != None + assert len(a2.employees["fields"]) == 4 + assert a2.employees["fields"][1] == "first_name" + assert len(a2.employees["rows"]) == 20 + +def test_column_name(): + assert a2.column_index("last_name") == 2 + assert a2.employee_id_column != None + +def test_first_name(): + assert a2.first_name(2) == "Lauren" + +def test_employee_find(): + match = a2.employee_find(3) + assert match[0][0] == "3" + assert len(match[0]) == 4 + +def test_employee_find_2(): + match = a2.employee_find_2(4) + assert match[0][0] == "4" + assert len(match[0]) == 4 + +def test_sort_by_last_name(): + rows = a2.sort_by_last_name() + assert len(rows) == 20 + assert rows[0][2]== "Bowman" + +def test_employee_dict(): + dict_result = a2.employee_dict(a2.employees["rows"][0]) + assert dict_result["last_name"] == "Bowman" + assert "employee_id" not in dict_result.keys() + +def test_all_employees_dict(): + dict_result = a2.all_employees_dict() + assert len(dict_result.keys()) == 20 + assert dict_result["9"]["first_name"] == "Phillip" \ No newline at end of file diff --git a/examples/assignment2.py b/examples/assignment2.py new file mode 100644 index 0000000..0e8718f --- /dev/null +++ b/examples/assignment2.py @@ -0,0 +1,65 @@ +import csv + +def read_employees(): + employees = {} + rows = [] + try: + with open("../csv/employees.csv", "r", newline="") as file: + reader = csv.reader(file) + first = True + for row in reader: + if first: + employees["fields"] = row + first=False + else: + rows.append(row) + employees["rows"] = rows + return employees + except BaseException as e: + print("An exception occurred: ", type(e).__name__) + raise e + +employees = read_employees() +print("employees: ", employees) + +def column_index(column_name): + return employees["fields"].index(column_name) + +employee_id_column=column_index("employee_id") + +def first_name(row_number): + first_name_index = column_index("first_name") + return employees["rows"][row_number][first_name_index] + +def employee_find(employee_id): + def employee_match(row): + return int(row[employee_id_column]) == employee_id + return list(filter(employee_match, employees["rows"])) + +def employee_find_2(employee_id): + return list(filter(lambda row : int(row[employee_id_column]) == employee_id, employees["rows"])) + +def sort_by_last_name(): + last_name_index = column_index("last_name") + employees["rows"].sort(key = lambda row : row[last_name_index]) + return employees["rows"] + +sort_by_last_name() +print("After sort: ", employees) + +def employee_dict(row): + return_dict = {} + for i, field in enumerate(employees["fields"]): + if field != "employee_id": + return_dict[field] = row[i] + return return_dict + +print("employee_dict: ", employee_dict(employees["rows"][2])) + +def all_employees_dict(): + return_dict = {} + for row in employees["rows"]: + return_dict[row[employee_id_column]]=employee_dict(row) + return return_dict + +print("all_employees_dict: ", all_employees_dict()) \ No newline at end of file From 15f975d18448547a8889b7e10407fa9d15e1e87e Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Wed, 12 Feb 2025 16:19:20 -0500 Subject: [PATCH 08/27] parameterized queries -- don't teach bad habits! --- examples/advanced_sql.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/examples/advanced_sql.py b/examples/advanced_sql.py index ea77e40..2a9cfd4 100644 --- a/examples/advanced_sql.py +++ b/examples/advanced_sql.py @@ -4,7 +4,10 @@ # The with statement is helpful, because it ensures that the connection # is closed at the end, even if an exception occurs - with sqlite3.connect("./db/lesson.db",isolation_level='IMMEDIATE') as conn: + with sqlite3.connect("./db/lesson.db",isolation_level='IMMEDIATE') as conn: + # The isolation_level means that a transaction is automatically opened. + # SQLite will open one automatically by default, but only with the + # first write request. cursor = conn.cursor() conn.execute("PRAGMA foreign_keys = 1") # This does a SELECT and a subquery @@ -42,34 +45,43 @@ stmt = """SELECT product_id FROM products ORDER BY price DESC LIMIT 5""" cursor.execute(stmt) result=cursor.fetchall() - print(result) + print("product list: ", result) products = result # Now we add the order, saving the returned order_id. This example uses a parameterized - # statement. It is not really necessary to use a parameterized statement when the - # values come from a trusted source, because no SQL injection could occur in that case. + # statement, as is best practice when putting variable values into SQL. stmt = f"""INSERT INTO orders (employee_id, customer_id) VALUES (?,?) RETURNING order_id""" cursor.execute(stmt,(employee_id, customer_id)) result = cursor.fetchone() print(result) order_id = result[0] values = [] + value_list = [] for i in range(5): - values.append(f"({order_id}, {products[i][0]}, 10)") - values_string = ",".join(values) - + values.append("(?,?, 10)") + value_list.append(order_id) + value_list.append(products[i][0]) # The product ids we want + values_string = ",".join(values) stmt = f"""INSERT INTO line_items (order_id, product_id, quantity) VALUES {values_string};""" + # This looks a little questionable, because we are using a formattted string for SQL. + # But the contents of the formatted string are created in the code, so it's safe -- + # There is no potential of a security attack. We do this to add the 5 line_item + # records with 1 insert statement. For the actual values we use a parameterized + # statement. print(stmt) - cursor.execute(stmt) + cursor.execute(stmt, value_list) conn.commit() - stmt=f"""SELECT l.line_item_id, l.quantity, p.product_name FROM line_items l JOIN products p ON - l.product_id = p.product_id WHERE l.order_id = {order_id};""" - cursor.execute(stmt) + stmt="""SELECT l.line_item_id, l.quantity, p.product_name FROM line_items l JOIN products p ON + l.product_id = p.product_id WHERE l.order_id = ?;""" + cursor.execute(stmt, (order_id,)) result = cursor.fetchall() for row in result: print(row) except Exception as e: - print(f"An exception occurred: {e}") + print(f"An exception occurred: {type(e).__name__}") + raise e # we pass the exception on so that we can see the stack. + # this is a shortcut -- often one would catch specific exceptions and not pass + # them on. else: print("All SQL operations completed.") \ No newline at end of file From 8a2483af3e2702aea0742e9472b8875d3ff88dba Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Sat, 15 Feb 2025 17:37:28 -0500 Subject: [PATCH 09/27] fix exception handling --- examples/advanced_sql.py | 14 ++++++++++---- examples/assignment2.py | 14 +++++++++++--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/examples/advanced_sql.py b/examples/advanced_sql.py index 2a9cfd4..fc8886a 100644 --- a/examples/advanced_sql.py +++ b/examples/advanced_sql.py @@ -1,4 +1,5 @@ import sqlite3 +import traceback try: # SQL operations can raise exceptions! @@ -78,10 +79,15 @@ for row in result: print(row) except Exception as e: - print(f"An exception occurred: {type(e).__name__}") - raise e # we pass the exception on so that we can see the stack. - # this is a shortcut -- often one would catch specific exceptions and not pass - # them on. + trace_back = traceback.extract_tb(e.__traceback__) + stack_trace = list() + for trace in trace_back: + stack_trace.append("File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3])) + print(f"Exception type: {type(e).__name__}") + message = str(e) + if message: + print(f"Exception message: {message}") + print(f"Stack trace: {stack_trace}") else: print("All SQL operations completed.") \ No newline at end of file diff --git a/examples/assignment2.py b/examples/assignment2.py index 0e8718f..d7cc552 100644 --- a/examples/assignment2.py +++ b/examples/assignment2.py @@ -1,4 +1,5 @@ import csv +import traceback def read_employees(): employees = {} @@ -15,9 +16,16 @@ def read_employees(): rows.append(row) employees["rows"] = rows return employees - except BaseException as e: - print("An exception occurred: ", type(e).__name__) - raise e + except Exception as e: + trace_back = traceback.extract_tb(e.__traceback__) + stack_trace = list() + for trace in trace_back: + stack_trace.append("File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3])) + print(f"Exception type: {type(e).__name__}") + message = str(e) + if message: + print(f"Exception message: {message}") + print(f"Stack trace: {stack_trace}") employees = read_employees() print("employees: ", employees) From a976ad872d827dc2af4a91ba7f32a835a74b932d Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Wed, 19 Feb 2025 19:42:47 -0500 Subject: [PATCH 10/27] add support for additional exercises on tuples, sets, etc --- assignment2/assignment2-test.py | 36 ++++++++++++++++- assignment2/minutes.csv | 47 ++++++++++++++++++++++ csv/minutes1.csv | 31 ++++++++++++++ csv/minutes2.csv | 31 ++++++++++++++ examples/assignment2.py | 71 ++++++++++++++++++++++++++++++++- 5 files changed, 213 insertions(+), 3 deletions(-) create mode 100644 assignment2/minutes.csv create mode 100644 csv/minutes1.csv create mode 100644 csv/minutes2.csv diff --git a/assignment2/assignment2-test.py b/assignment2/assignment2-test.py index 87dd90b..68560d8 100644 --- a/assignment2/assignment2-test.py +++ b/assignment2/assignment2-test.py @@ -1,4 +1,5 @@ import assignment2 as a2 +import os def test_read_employees(): employees = a2.read_employees() @@ -13,7 +14,7 @@ def test_column_name(): assert a2.employee_id_column != None def test_first_name(): - assert a2.first_name(2) == "Lauren" + assert a2.first_name(2) in ("David","Lauren") # values before and after sort def test_employee_find(): match = a2.employee_find(3) @@ -38,4 +39,35 @@ def test_employee_dict(): def test_all_employees_dict(): dict_result = a2.all_employees_dict() assert len(dict_result.keys()) == 20 - assert dict_result["9"]["first_name"] == "Phillip" \ No newline at end of file + assert dict_result["9"]["first_name"] == "Phillip" + +def test_get_this_value(): + assert a2.get_this_value() == "ABC" + +def test_set_that_secret(): + import custom_module + a2.set_that_secret("swordfish") + assert custom_module.secret == "swordfish" + +def test_read_minutes(): + d1, d2 = a2.read_minutes() + assert d1["rows"][1] == ("Tony Henderson","November 15, 1991") + assert d2["rows"][2] == ("Sarah Murray","November 19, 1988") + assert a2.minutes1 != None + +def test_create_minutes_set(): + minutes_set = a2.create_minutes_set() + assert type(minutes_set).__name__ == "set" + assert len(minutes_set) == 46 + assert a2.minutes_set != None + +def test_create_minutes_list(): + minutes_list = a2.create_minutes_list() + assert type(minutes_list[0][1]).__name__ == "datetime" + assert type(minutes_list[0]).__name__ == "tuple" + assert a2.minutes_list != None + +def test_write_sorted_list(): + sorted_list = a2.write_sorted_list() + assert sorted_list[0] == ("Jason Tucker","September 20, 1980") + assert os.access("./minutes.csv", os.F_OK) == True \ No newline at end of file diff --git a/assignment2/minutes.csv b/assignment2/minutes.csv new file mode 100644 index 0000000..0acabb7 --- /dev/null +++ b/assignment2/minutes.csv @@ -0,0 +1,47 @@ +Name,Date +Jason Tucker,"September 20, 1980" +Austin Hester,"March 8, 1981" +Daniel Jackson,"October 2, 1981" +Mrs. Samantha Johnson,"December 17, 1981" +Joseph Harris,"March 3, 1982" +Mrs. Samantha Johnson,"March 12, 1982" +Gina Maldonado,"December 16, 1982" +Mrs. Samantha Johnson,"December 23, 1982" +Yesenia Smith,"August 10, 1983" +Lori Martin,"February 5, 1984" +Jonathan Parrish,"June 12, 1984" +Mrs. Samantha Johnson,"July 20, 1984" +Amanda Brown,"August 8, 1984" +Sarah Murray,"October 30, 1984" +Mrs. Samantha Johnson,"November 28, 1984" +Austin Hester,"June 4, 1985" +Jonathan Parrish,"March 18, 1986" +Yesenia Smith,"May 6, 1986" +Daniel Jackson,"December 13, 1986" +Gina Maldonado,"February 13, 1987" +Kimberly Stewart,"December 12, 1987" +Mrs. Samantha Johnson,"July 10, 1988" +Sarah Murray,"August 16, 1988" +Aaron Kaufman,"October 24, 1988" +Tony Henderson,"November 7, 1988" +Sarah Murray,"November 19, 1988" +Austin Hester,"January 18, 1989" +Joseph Harris,"March 1, 1989" +Gina Maldonado,"April 7, 1989" +Aaron Kaufman,"November 14, 1989" +Daniel Jackson,"April 8, 1990" +Aaron Kaufman,"May 1, 1990" +Aaron Kaufman,"July 21, 1990" +Tony Henderson,"October 4, 1990" +Yesenia Smith,"November 23, 1990" +Joseph Harris,"April 3, 1991" +Jason Tucker,"April 30, 1991" +Matthew Russell,"May 31, 1991" +Lori Martin,"July 8, 1991" +Mrs. Samantha Johnson,"July 23, 1991" +Tony Henderson,"November 15, 1991" +Gina Maldonado,"February 9, 1992" +Sarah Murray,"June 27, 1992" +Gina Maldonado,"October 31, 1992" +Austin Hester,"December 10, 1992" +Mrs. Samantha Johnson,"December 12, 1992" diff --git a/csv/minutes1.csv b/csv/minutes1.csv new file mode 100644 index 0000000..e9fd8d9 --- /dev/null +++ b/csv/minutes1.csv @@ -0,0 +1,31 @@ +Name,Date +Gina Maldonado,"October 31, 1992" +Tony Henderson,"November 15, 1991" +Jonathan Parrish,"June 12, 1984" +Jonathan Parrish,"June 12, 1984" +Mrs. Samantha Johnson,"July 20, 1984" +Mrs. Samantha Johnson,"July 20, 1984" +Joseph Harris,"March 3, 1982" +Aaron Kaufman,"November 14, 1989" +Tony Henderson,"November 7, 1988" +Tony Henderson,"November 7, 1988" +Tony Henderson,"November 7, 1988" +Mrs. Samantha Johnson,"July 23, 1991" +Kimberly Stewart,"December 12, 1987" +Daniel Jackson,"October 2, 1981" +Daniel Jackson,"October 2, 1981" +Joseph Harris,"April 3, 1991" +Joseph Harris,"April 3, 1991" +Mrs. Samantha Johnson,"December 23, 1982" +Mrs. Samantha Johnson,"December 12, 1992" +Tony Henderson,"October 4, 1990" +Yesenia Smith,"August 10, 1983" +Yesenia Smith,"August 10, 1983" +Joseph Harris,"March 1, 1989" +Amanda Brown,"August 8, 1984" +Aaron Kaufman,"October 24, 1988" +Aaron Kaufman,"July 21, 1990" +Gina Maldonado,"April 7, 1989" +Austin Hester,"December 10, 1992" +Austin Hester,"December 10, 1992" +Daniel Jackson,"December 13, 1986" diff --git a/csv/minutes2.csv b/csv/minutes2.csv new file mode 100644 index 0000000..8169be7 --- /dev/null +++ b/csv/minutes2.csv @@ -0,0 +1,31 @@ +Name,Date +Austin Hester,"March 8, 1981" +Mrs. Samantha Johnson,"July 10, 1988" +Sarah Murray,"November 19, 1988" +Sarah Murray,"November 19, 1988" +Sarah Murray,"June 27, 1992" +Gina Maldonado,"February 13, 1987" +Yesenia Smith,"November 23, 1990" +Austin Hester,"January 18, 1989" +Jason Tucker,"April 30, 1991" +Daniel Jackson,"April 8, 1990" +Sarah Murray,"October 30, 1984" +Mrs. Samantha Johnson,"November 28, 1984" +Mrs. Samantha Johnson,"November 28, 1984" +Jason Tucker,"September 20, 1980" +Lori Martin,"July 8, 1991" +Gina Maldonado,"December 16, 1982" +Mrs. Samantha Johnson,"December 17, 1981" +Gina Maldonado,"February 9, 1992" +Lori Martin,"February 5, 1984" +Austin Hester,"June 4, 1985" +Aaron Kaufman,"May 1, 1990" +Yesenia Smith,"May 6, 1986" +Yesenia Smith,"May 6, 1986" +Mrs. Samantha Johnson,"March 12, 1982" +Sarah Murray,"August 16, 1988" +Matthew Russell,"May 31, 1991" +Matthew Russell,"May 31, 1991" +Jonathan Parrish,"March 18, 1986" +Jonathan Parrish,"March 18, 1986" +Jonathan Parrish,"March 18, 1986" diff --git a/examples/assignment2.py b/examples/assignment2.py index d7cc552..e466758 100644 --- a/examples/assignment2.py +++ b/examples/assignment2.py @@ -1,5 +1,7 @@ import csv import traceback +import os +from datetime import datetime def read_employees(): employees = {} @@ -70,4 +72,71 @@ def all_employees_dict(): return_dict[row[employee_id_column]]=employee_dict(row) return return_dict -print("all_employees_dict: ", all_employees_dict()) \ No newline at end of file +print("all_employees_dict: ", all_employees_dict()) + +def get_this_value(): + return os.getenv("THISVALUE") + +import custom_module +def set_that_secret(new_secret): + custom_module.set_secret(new_secret) + +set_that_secret("open, sesame!") +print("module secret now: ", custom_module.secret) + +def read_minutes(): + dict1 = {} + dict2 = {} + with open("../csv/minutes1.csv") as file: + reader = csv.reader(file) + list1 = [] + first = True + for row in reader: + if first: + dict1["fields"] = row + first = False + else: + list1.append(tuple(row)) + dict1["rows"] = list1 + with open("../csv/minutes2.csv") as file: + reader = csv.reader(file) + list1 = [] + first = True + for row in reader: + if first: + dict2["fields"] = row + first = False + else: + list1.append(tuple(row)) + dict2["rows"] = list1 + return dict1,dict2 + +minutes1, minutes2 = read_minutes() + +print(minutes1, minutes2) + +def create_minutes_set(): + return set(minutes1["rows"]).union(set(minutes2["rows"])) + +minutes_set = create_minutes_set() +print(minutes_set) + +def create_minutes_list(): + minutes_list1 = list(minutes_set) + minutes_list1 = list(map(lambda x: (x[0], datetime.strptime(x[1], "%B %d, %Y")), minutes_list1)) + return minutes_list1 + +minutes_list = create_minutes_list() +print(minutes_list) + +def write_sorted_list(): + minutes_list.sort(key= lambda x: x[1]) + minutes_list1 = list(map(lambda row: (row[0], datetime.strftime(row[1], "%B %-d, %Y")), minutes_list)) + with open("./minutes.csv","w") as file: + writer = csv.writer(file) + writer.writerow(minutes1["fields"]) + for row in minutes_list1: + writer.writerow(row) + return minutes_list1 + +write_sorted_list() \ No newline at end of file From afd51c546d0b62b12d615f906db03cf92757fc7f Mon Sep 17 00:00:00 2001 From: Tom Arns Date: Tue, 25 Feb 2025 11:51:42 -0800 Subject: [PATCH 11/27] revisions to repo setup. Handle ssh authentication and working updates. --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e536faf..23daae0 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,14 @@ Before using this repository, you must install Python and must complete the rest To use this repository: 1. Sign into your GitHub, and create a repository called python_homework. It must be a public repository. Do not create a .gitignore or a README.md. -2. On your laptop, clone the [https://github.com/Code-the-Dream-School/python_homework](https://github.com/Code-the-Dream-School/python_homework) repository. (Do not clone the repository you just created.) -3. Change to the python_homework directory. Enter the following commands: +2. On your computer, clone the [https://github.com/Code-the-Dream-School/python_homework](https://github.com/Code-the-Dream-School/python_homework) repository. (Do not clone the repository you just created.) +3. Change to the python_homework directory you just cloned. Enter the following commands: ```shell +# if you use ssh authentication: +git remote set-url origin git@github.com/your-github-id/python_homework +# if you use token based authentication: git remote set-url origin https://github.com/your-github-id/python_homework + git remote add upstream https://github.com/Code-the-Dream-School/python_homework git push origin main ``` @@ -24,7 +28,7 @@ python -m venv .venv source .venv/Scripts/activate code . ``` -4. Important: Open the VSCode command pallette (ctrl-shift P). In the `Python: Select Interpreter` option, choose the one with `.venv`. If you have any terminal sessions open, close them, and open a new one. You will see `(.venv)` in your terminal prompt. +4. Important: Open the VSCode command pallette (ctrl-shift P). In the `Python: Select Interpreter` option, choose the one with `.venv`. You can use the search box at the top to find it. If you have any terminal sessions open, close them, and open a new one. You will see `(.venv)` in your terminal prompt. 5. From the VSCode terminal session, enter the command: ```shell pip install -r requirements.txt From ec3ec0c12d0b187d93a5859e3c9fd6e058bf849e Mon Sep 17 00:00:00 2001 From: Tom Arns Date: Fri, 28 Feb 2025 13:45:29 -0800 Subject: [PATCH 12/27] added assignment3 directory, added unit tests for the first task --- assignment3/assignment3-test.py | 22 ++++++++++++++++++++++ assignment3/assignment3.py | 0 2 files changed, 22 insertions(+) create mode 100644 assignment3/assignment3-test.py create mode 100644 assignment3/assignment3.py diff --git a/assignment3/assignment3-test.py b/assignment3/assignment3-test.py new file mode 100644 index 0000000..6acebab --- /dev/null +++ b/assignment3/assignment3-test.py @@ -0,0 +1,22 @@ +import assignment3 as a3 +import numpy as np +import pandas as pd +import os + +test1_df = pd.DataFrame({ 'Name': ['Alice', 'Bob', 'charlie'], + 'Age': [25, 30, 35], + 'City': ['New York', 'Los Angeles', 'Chicago']}) + +def test_data_frame_from_dictionary(): + assert test1_df.equals(a3.task1_data_frame) + +def test_added_column(): + assert a3.task1_with_salary['Salary'].equals(pd.Series([70000, 80000, 90000])) + +def test_increment_column(): + assert a3.task1_older["Age"].equals(pd.Series([26, 31, 36])) + +def test_write_csv(): + assert os.access("./employees.csv", os.F_OK) == True + + diff --git a/assignment3/assignment3.py b/assignment3/assignment3.py new file mode 100644 index 0000000..e69de29 From dee694e0d535072bd421ef944ccfc56e2db0ca05 Mon Sep 17 00:00:00 2001 From: Tom Arns Date: Tue, 4 Mar 2025 18:09:35 -0800 Subject: [PATCH 13/27] added unit tests and a new section on data cleaning, removed describe() and corr() --- assignment3/assignment3-test.py | 110 ++++++++++++++++++++++++++++++++ assignment3/dirty_data.csv | 8 +++ 2 files changed, 118 insertions(+) create mode 100644 assignment3/dirty_data.csv diff --git a/assignment3/assignment3-test.py b/assignment3/assignment3-test.py index 6acebab..d1ac1af 100644 --- a/assignment3/assignment3-test.py +++ b/assignment3/assignment3-test.py @@ -7,6 +7,7 @@ 'Age': [25, 30, 35], 'City': ['New York', 'Los Angeles', 'Chicago']}) +# Task 1 def test_data_frame_from_dictionary(): assert test1_df.equals(a3.task1_data_frame) @@ -18,5 +19,114 @@ def test_increment_column(): def test_write_csv(): assert os.access("./employees.csv", os.F_OK) == True + # make sure there is no index + assert pd.read_csv('employees.csv').shape == (3, 4) + + + +# Task 2 +def test_read_data_frame_from_csv(): + assert a3.task1_older.equals(a3.task2_employees) + +test2_json_df = pd.DataFrame({ 'Name': ['Eve', 'Frank'], + 'Age': [28, 40], + 'City': ['Miami', 'Seattle'], + 'Salary': [60000, 95000]}) + +def test_read_data_frame_from_json(): + assert os.access("./additional_employees.json", os.F_OK) == True + assert a3.json_employees.equals(test2_json_df) + +def test_concat_json_employees(): + assert a3.more_employees.equals(pd.concat([a3.task2_employees, a3.json_employees], ignore_index=True)) + assert a3.more_employees.shape == (5, 4) + + +# Task 3 +def test_head(): + assert a3.first_three.equals(a3.more_employees.head(3)) + +def test_tail(): + assert a3.last_two.equals(a3.more_employees.tail(2)) + +def test_shape(): + assert a3.employee_shape == (5, 4) + + +# Task 4 +from io import StringIO +sample_data = """Name,Age,Salary,Hire Date,Department +Alice, 29,50000,2021/01/15, Sales +Bob, 32, unknown,2020-03-18,MARKETING + charlie, NaN, 70000,3/25/2019,marketinG +Dana, 41, n/a,2020/12/01, HR +Eve, 24,65000,2021/06/07, hr +Frank, 32,75000, 2019-07-11,Sales +Bob, 32, unknown,2020-03-18,MARKETING +""" +# Read into DataFrame +ddf = pd.read_csv(StringIO(sample_data)) +tdf = ddf.copy() + +# Perform the same cleaning steps +tdf.drop_duplicates(inplace=True) +tdf['Age'] = pd.to_numeric(tdf['Age'], errors='coerce') +tdf['Salary'] = tdf['Salary'].replace(['unknown', 'n/a'], pd.NA) +tdf['Salary'] = pd.to_numeric(tdf['Salary'], errors='coerce') +tdf['Hire Date'] = pd.to_datetime(tdf['Hire Date'], errors='coerce') +tdf['Name'] = tdf['Name'].str.strip() +tdf['Department'] = tdf['Department'].str.strip().str.upper() + +def test_dirty_data_read(): + assert a3.dirty_data.equals(ddf) + +def test_no_duplicate_rows(): + assert len(a3.clean_data) == 6 + +def test_age_numeric(): + assert pd.api.types.is_numeric_dtype(a3.clean_data['Age']) + assert a3.clean_data['Age'].dropna().between(1, 100).all() + +def test_salary_numeric(): + assert pd.api.types.is_numeric_dtype(a3.clean_data['Salary']) + +def test_no_missing_age_or_salary(): + assert not a3.clean_data['Age'].isnull().any() + assert not a3.clean_data['Salary'].isnull().any() + +def test_hire_date_datetime(): + assert pd.api.types.is_datetime64_any_dtype(a3.clean_data['Hire Date']) + +def test_department_uppercase(): + all_upper = True + for dept in a3.clean_data['Department']: + if not dept.isupper(): + all_upper = False + assert all_upper + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assignment3/dirty_data.csv b/assignment3/dirty_data.csv new file mode 100644 index 0000000..0eb86b4 --- /dev/null +++ b/assignment3/dirty_data.csv @@ -0,0 +1,8 @@ +Name,Age,Salary,Hire Date,Department +Alice, 29,50000,2021/01/15, Sales +Bob, 32, unknown,2020-03-18,MARKETING + charlie, NaN, 70000,3/25/2019,marketinG +Dana, 41, n/a,2020/12/01, HR +Eve, 24,65000,2021/06/07, hr +Frank, 32,75000, 2019-07-11,Sales +Bob, 32, unknown,2020-03-18,MARKETING From 318f522c5824c700c4cd30047f5a9af2a1ccedea Mon Sep 17 00:00:00 2001 From: Tom Arns Date: Sat, 8 Mar 2025 16:13:09 -0800 Subject: [PATCH 14/27] fixed missing .git in ssh suthentication oprion --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 23daae0..7f43c86 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ To use this repository: 3. Change to the python_homework directory you just cloned. Enter the following commands: ```shell # if you use ssh authentication: -git remote set-url origin git@github.com/your-github-id/python_homework +git remote set-url origin git@github.com/your-github-id/python_homework.git # if you use token based authentication: git remote set-url origin https://github.com/your-github-id/python_homework @@ -42,4 +42,4 @@ When you have completed the lesson, add and commit your changes and push them to Once you have created the pull request, include a link for the pull request in your homework submission. Your reviewer will be notified, and will approve your request or ask for rework. **Do not merge your pull request until your reviewer has approved it.** -Good luck with the class! \ No newline at end of file +Good luck with the class! From aa5007ad8c9ea445d54cec438071e9446f364ff9 Mon Sep 17 00:00:00 2001 From: Tom Arns Date: Mon, 10 Mar 2025 15:31:45 -0700 Subject: [PATCH 15/27] remove assignment1 and 2 example solutions. The solutions have been moved to the mentor guidebook. --- examples/assignment1.py | 144 ---------------------------------------- examples/assignment2.py | 142 --------------------------------------- 2 files changed, 286 deletions(-) delete mode 100644 examples/assignment1.py delete mode 100644 examples/assignment2.py diff --git a/examples/assignment1.py b/examples/assignment1.py deleted file mode 100644 index 110fcaa..0000000 --- a/examples/assignment1.py +++ /dev/null @@ -1,144 +0,0 @@ -# Write your code here. -def hello(): - return "Hello!" - -print("hello: ", hello()) - -def greet(name): - return f"Hello, {name}!" - -print("greet: ", greet("Fred")) - -def calc(v1, v2, op="multiply"): - try: - match op: - case "multiply": - return v1 * v2 - case "add": - return v1 + v2 - case "subtract": - return v1 - v2 - case "divide": - return v1 / v2 - case "power": - return v1 ** v2 - case "modulo": - return v1 % v2 - case "int_divide": - return v1 // v2 - case _: - return "unsupported operation" - except ZeroDivisionError: - return "You can't divide by 0!" - except TypeError: - return f"You can't {op} those values!" - -print("calc: ", calc(7,8,"add")) - -def data_type_conversion(value, type_name): - try: - match type_name: - case "int": - return int(value) - case "float": - return float(value) - case "str": - return str(value) - except ValueError: - return f"You can't convert {value} into a {type_name}." - -print("data_type_conversion: ", data_type_conversion(5.23, "int")) - -def grade(*args): - try: - avg = sum(args) / len(args) - if avg >= 90: - return "A" - elif avg >= 80: - return "B" - elif avg >= 70: - return "C" - elif avg >= 60: - return "D" - else: - return "F" - except TypeError: - return "Invalid data was provided." - -print("grade: ", grade(90,79, 95, 80)) - -def repeat(string, count): - out_string = string - for i in range(1,count): - out_string += string - return out_string - -print("repeat: ", repeat("good ",3)) - -def student_scores(operation, **kwargs): - if operation == "best": - best_value = 0 - for key, value in kwargs.items(): - if value > best_value: - best_name = key - best_value = value - return best_name - else: - return sum(kwargs.values()) / len(kwargs.values()) - -print("student_scores: ", student_scores("best", Bob=70, Susan=90)) - -def titleize(title): - title_list = title.split() - little_words = ["a", "on", "an", "the", "of", "and", "is", "in"] - for i, word in enumerate(title_list): - if word not in little_words: - title_list[i] = word.capitalize() - title_list[0] = title_list[0].capitalize() - title_list[-1] = title_list[-1].capitalize() - return " ".join(title_list) - -print("titleize: ", titleize("dancing at the rascal fair")) - -def hangman(secret, guess): - report = "" - for c in secret: - if c in guess: - report += c - else: - report += "_" - return report - -print("hangman: ", hangman("obscurely", "bur")) - -def pig_latin(s): - vowels = "aeiouAEIOU" - out_string = "" - start_string = "" - rest_string = "" - for ch in s: - if (ch == " "): - if (rest_string): - if len(out_string) > 0: - out_string += " " - out_string += rest_string + start_string + "ay" - rest_string = "" - start_string = "" - elif len(rest_string) > 0: - rest_string += ch - elif (ch == "u" or ch == "U") and len(start_string) > 0 and \ - (start_string[-1] == "q" or start_string[-1] == "Q"): - start_string += ch - elif ch in vowels: - rest_string += ch - elif len(rest_string) > 0: - rest_string += ch - else: - start_string += ch - if len(rest_string) > 0: - if len(out_string) > 0: - out_string += " " - out_string += rest_string + start_string + "ay" - return out_string - -print("pig_latin: ", pig_latin("it is forbidden to spit on cats")) diff --git a/examples/assignment2.py b/examples/assignment2.py deleted file mode 100644 index e466758..0000000 --- a/examples/assignment2.py +++ /dev/null @@ -1,142 +0,0 @@ -import csv -import traceback -import os -from datetime import datetime - -def read_employees(): - employees = {} - rows = [] - try: - with open("../csv/employees.csv", "r", newline="") as file: - reader = csv.reader(file) - first = True - for row in reader: - if first: - employees["fields"] = row - first=False - else: - rows.append(row) - employees["rows"] = rows - return employees - except Exception as e: - trace_back = traceback.extract_tb(e.__traceback__) - stack_trace = list() - for trace in trace_back: - stack_trace.append("File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3])) - print(f"Exception type: {type(e).__name__}") - message = str(e) - if message: - print(f"Exception message: {message}") - print(f"Stack trace: {stack_trace}") - -employees = read_employees() -print("employees: ", employees) - -def column_index(column_name): - return employees["fields"].index(column_name) - -employee_id_column=column_index("employee_id") - -def first_name(row_number): - first_name_index = column_index("first_name") - return employees["rows"][row_number][first_name_index] - -def employee_find(employee_id): - def employee_match(row): - return int(row[employee_id_column]) == employee_id - return list(filter(employee_match, employees["rows"])) - -def employee_find_2(employee_id): - return list(filter(lambda row : int(row[employee_id_column]) == employee_id, employees["rows"])) - -def sort_by_last_name(): - last_name_index = column_index("last_name") - employees["rows"].sort(key = lambda row : row[last_name_index]) - return employees["rows"] - -sort_by_last_name() -print("After sort: ", employees) - -def employee_dict(row): - return_dict = {} - for i, field in enumerate(employees["fields"]): - if field != "employee_id": - return_dict[field] = row[i] - return return_dict - -print("employee_dict: ", employee_dict(employees["rows"][2])) - -def all_employees_dict(): - return_dict = {} - for row in employees["rows"]: - return_dict[row[employee_id_column]]=employee_dict(row) - return return_dict - -print("all_employees_dict: ", all_employees_dict()) - -def get_this_value(): - return os.getenv("THISVALUE") - -import custom_module -def set_that_secret(new_secret): - custom_module.set_secret(new_secret) - -set_that_secret("open, sesame!") -print("module secret now: ", custom_module.secret) - -def read_minutes(): - dict1 = {} - dict2 = {} - with open("../csv/minutes1.csv") as file: - reader = csv.reader(file) - list1 = [] - first = True - for row in reader: - if first: - dict1["fields"] = row - first = False - else: - list1.append(tuple(row)) - dict1["rows"] = list1 - with open("../csv/minutes2.csv") as file: - reader = csv.reader(file) - list1 = [] - first = True - for row in reader: - if first: - dict2["fields"] = row - first = False - else: - list1.append(tuple(row)) - dict2["rows"] = list1 - return dict1,dict2 - -minutes1, minutes2 = read_minutes() - -print(minutes1, minutes2) - -def create_minutes_set(): - return set(minutes1["rows"]).union(set(minutes2["rows"])) - -minutes_set = create_minutes_set() -print(minutes_set) - -def create_minutes_list(): - minutes_list1 = list(minutes_set) - minutes_list1 = list(map(lambda x: (x[0], datetime.strptime(x[1], "%B %d, %Y")), minutes_list1)) - return minutes_list1 - -minutes_list = create_minutes_list() -print(minutes_list) - -def write_sorted_list(): - minutes_list.sort(key= lambda x: x[1]) - minutes_list1 = list(map(lambda row: (row[0], datetime.strftime(row[1], "%B %-d, %Y")), minutes_list)) - with open("./minutes.csv","w") as file: - writer = csv.writer(file) - writer.writerow(minutes1["fields"]) - for row in minutes_list1: - writer.writerow(row) - return minutes_list1 - -write_sorted_list() \ No newline at end of file From 459e5d240df9d94e7155bfde48e84be97f279267 Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Thu, 13 Mar 2025 19:02:14 -0400 Subject: [PATCH 16/27] examples now in mentor guidebook --- examples/advanced_sql.py | 93 ---------------------------------------- 1 file changed, 93 deletions(-) delete mode 100644 examples/advanced_sql.py diff --git a/examples/advanced_sql.py b/examples/advanced_sql.py deleted file mode 100644 index fc8886a..0000000 --- a/examples/advanced_sql.py +++ /dev/null @@ -1,93 +0,0 @@ -import sqlite3 -import traceback - -try: # SQL operations can raise exceptions! - - # The with statement is helpful, because it ensures that the connection - # is closed at the end, even if an exception occurs - with sqlite3.connect("./db/lesson.db",isolation_level='IMMEDIATE') as conn: - # The isolation_level means that a transaction is automatically opened. - # SQLite will open one automatically by default, but only with the - # first write request. - cursor = conn.cursor() - conn.execute("PRAGMA foreign_keys = 1") - # This does a SELECT and a subquery - stmt = """SELECT o.order_id, l.line_item_id, p.product_name FROM orders - o JOIN line_items l on o.order_id = l.order_id JOIN products p on - l.product_id = p.product_id WHERE o.order_id IN - (SELECT order_id from orders ORDER BY order_id limit 5);""" - cursor.execute(stmt) - result = cursor.fetchall() - for row in result: - print(row) - - # This retrieves the first 5 orders joined with the line_items and products tables, - # and aggregates (SUM) the quantity by the price to give the cost of each order - stmt = """SELECT o.order_id, SUM(l.quantity * p.price) FROM orders o JOIN line_items l ON - o.order_id = l.order_id JOIN products p on l.product_id = p.product_id GROUP BY o.order_id - ORDER BY o.order_id LIMIT 5;""" - cursor.execute(stmt) - result = cursor.fetchall() - for row in result: - print(row) - - # This creates a new order with corresponding line_items. First, we get the ids of - # the customer, the employee, and the products. - stmt = """SELECT customer_id FROM customers WHERE customer_name = \"Perez and Sons\";""" - cursor.execute(stmt) - result = cursor.fetchone() - print(result) - customer_id = result[0] - stmt = """SELECT employee_id FROM employees WHERE first_name = \"Miranda\" AND last_name = \"Harris\";""" - cursor.execute(stmt) - result = cursor.fetchone() - print(result) - employee_id = result[0] - stmt = """SELECT product_id FROM products ORDER BY price DESC LIMIT 5""" - cursor.execute(stmt) - result=cursor.fetchall() - print("product list: ", result) - products = result - - # Now we add the order, saving the returned order_id. This example uses a parameterized - # statement, as is best practice when putting variable values into SQL. - stmt = f"""INSERT INTO orders (employee_id, customer_id) VALUES (?,?) RETURNING order_id""" - cursor.execute(stmt,(employee_id, customer_id)) - result = cursor.fetchone() - print(result) - order_id = result[0] - values = [] - value_list = [] - for i in range(5): - values.append("(?,?, 10)") - value_list.append(order_id) - value_list.append(products[i][0]) # The product ids we want - values_string = ",".join(values) - stmt = f"""INSERT INTO line_items (order_id, product_id, quantity) VALUES {values_string};""" - # This looks a little questionable, because we are using a formattted string for SQL. - # But the contents of the formatted string are created in the code, so it's safe -- - # There is no potential of a security attack. We do this to add the 5 line_item - # records with 1 insert statement. For the actual values we use a parameterized - # statement. - print(stmt) - cursor.execute(stmt, value_list) - conn.commit() - stmt="""SELECT l.line_item_id, l.quantity, p.product_name FROM line_items l JOIN products p ON - l.product_id = p.product_id WHERE l.order_id = ?;""" - cursor.execute(stmt, (order_id,)) - result = cursor.fetchall() - for row in result: - print(row) -except Exception as e: - trace_back = traceback.extract_tb(e.__traceback__) - stack_trace = list() - for trace in trace_back: - stack_trace.append("File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3])) - print(f"Exception type: {type(e).__name__}") - message = str(e) - if message: - print(f"Exception message: {message}") - print(f"Stack trace: {stack_trace}") -else: - print("All SQL operations completed.") - \ No newline at end of file From 47d69285d4cc0db64deb9d0d79d963304ab06c11 Mon Sep 17 00:00:00 2001 From: Tom Arns Date: Thu, 13 Mar 2025 20:49:09 -0700 Subject: [PATCH 17/27] fixed typo in ssh remote url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f43c86..90f33e8 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ To use this repository: 3. Change to the python_homework directory you just cloned. Enter the following commands: ```shell # if you use ssh authentication: -git remote set-url origin git@github.com/your-github-id/python_homework.git +git remote set-url origin git@github.com:your-github-id/python_homework.git # if you use token based authentication: git remote set-url origin https://github.com/your-github-id/python_homework From af78425b668a2414ddf41219f1f49694ed1ffa04 Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Thu, 20 Mar 2025 22:46:59 -0400 Subject: [PATCH 18/27] create folders for assignment 9 and 10 homework --- assignment10/.keep | 0 assignment9/.keep | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assignment10/.keep create mode 100644 assignment9/.keep diff --git a/assignment10/.keep b/assignment10/.keep new file mode 100644 index 0000000..e69de29 diff --git a/assignment9/.keep b/assignment9/.keep new file mode 100644 index 0000000..e69de29 From f00a64f7a8f6912c59577b920da57a005dcd1e10 Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Thu, 20 Mar 2025 23:20:49 -0400 Subject: [PATCH 19/27] added folders for assignments 7 and 8 as well --- assignment7/.keep | 0 assignment8/.keep | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assignment7/.keep create mode 100644 assignment8/.keep diff --git a/assignment7/.keep b/assignment7/.keep new file mode 100644 index 0000000..e69de29 diff --git a/assignment8/.keep b/assignment8/.keep new file mode 100644 index 0000000..e69de29 From 6583442e13d59fb41918c5b9719830ddd9c2c6cc Mon Sep 17 00:00:00 2001 From: Tom Arns Date: Fri, 21 Mar 2025 08:45:17 -0700 Subject: [PATCH 20/27] fixed test to match problem description - case error --- assignment3/assignment3-test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment3/assignment3-test.py b/assignment3/assignment3-test.py index d1ac1af..b0a14ca 100644 --- a/assignment3/assignment3-test.py +++ b/assignment3/assignment3-test.py @@ -3,7 +3,7 @@ import pandas as pd import os -test1_df = pd.DataFrame({ 'Name': ['Alice', 'Bob', 'charlie'], +test1_df = pd.DataFrame({ 'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35], 'City': ['New York', 'Los Angeles', 'Chicago']}) From 1a29712e95f467e127cac9683359682a0c0e0ac4 Mon Sep 17 00:00:00 2001 From: "John R. McGarvey" Date: Mon, 31 Mar 2025 00:14:05 -0400 Subject: [PATCH 21/27] add the assignment12 folder --- assignment12/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assignment12/.keep diff --git a/assignment12/.keep b/assignment12/.keep new file mode 100644 index 0000000..e69de29 From 197ea81b7c2ef08e721b476bb7b7e8e7882876c9 Mon Sep 17 00:00:00 2001 From: Rick Martin Date: Wed, 2 Apr 2025 09:48:21 -0400 Subject: [PATCH 22/27] Added test for NaTs in Hire Date field --- assignment3/assignment3-test.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/assignment3/assignment3-test.py b/assignment3/assignment3-test.py index b0a14ca..a0576a0 100644 --- a/assignment3/assignment3-test.py +++ b/assignment3/assignment3-test.py @@ -104,9 +104,10 @@ def test_department_uppercase(): all_upper = False assert all_upper - - - +# If dates are not converted properly with form="mixed" will end up with NaTs +def test_hire_date_notNAT(): + nat_count = a3.clean_data['Hire Date'].isna().sum() + assert nat_count == 0 From a938922cda81e2222faa3dfebd7ffc86d1eee0dc Mon Sep 17 00:00:00 2001 From: Rick Martin Date: Wed, 2 Apr 2025 09:54:41 -0400 Subject: [PATCH 23/27] Added test for NaTs in Hire Date field again --- assignment3/assignment3-test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment3/assignment3-test.py b/assignment3/assignment3-test.py index a0576a0..5843753 100644 --- a/assignment3/assignment3-test.py +++ b/assignment3/assignment3-test.py @@ -104,7 +104,7 @@ def test_department_uppercase(): all_upper = False assert all_upper -# If dates are not converted properly with form="mixed" will end up with NaTs +# April 2: If dates are not converted properly with form="mixed" will end up with NaTs def test_hire_date_notNAT(): nat_count = a3.clean_data['Hire Date'].isna().sum() assert nat_count == 0 From 69abdff6fdb0bf1da16fc5f1987ddebcfbe4a993 Mon Sep 17 00:00:00 2001 From: Tom Arns Date: Fri, 25 Jul 2025 11:20:19 -0700 Subject: [PATCH 24/27] rename a3 to a4 --- .../assignment4-test.py | 42 +++++++++---------- .../assignment4.py | 0 {assignment3 => assignment4}/dirty_data.csv | 0 3 files changed, 21 insertions(+), 21 deletions(-) rename assignment3/assignment3-test.py => assignment4/assignment4-test.py (67%) rename assignment3/assignment3.py => assignment4/assignment4.py (100%) rename {assignment3 => assignment4}/dirty_data.csv (100%) diff --git a/assignment3/assignment3-test.py b/assignment4/assignment4-test.py similarity index 67% rename from assignment3/assignment3-test.py rename to assignment4/assignment4-test.py index 5843753..3ad40a9 100644 --- a/assignment3/assignment3-test.py +++ b/assignment4/assignment4-test.py @@ -1,4 +1,4 @@ -import assignment3 as a3 +import assignment4 as a4 import numpy as np import pandas as pd import os @@ -9,13 +9,13 @@ # Task 1 def test_data_frame_from_dictionary(): - assert test1_df.equals(a3.task1_data_frame) + assert test1_df.equals(a4.task1_data_frame) def test_added_column(): - assert a3.task1_with_salary['Salary'].equals(pd.Series([70000, 80000, 90000])) + assert a4.task1_with_salary['Salary'].equals(pd.Series([70000, 80000, 90000])) def test_increment_column(): - assert a3.task1_older["Age"].equals(pd.Series([26, 31, 36])) + assert a4.task1_older["Age"].equals(pd.Series([26, 31, 36])) def test_write_csv(): assert os.access("./employees.csv", os.F_OK) == True @@ -26,7 +26,7 @@ def test_write_csv(): # Task 2 def test_read_data_frame_from_csv(): - assert a3.task1_older.equals(a3.task2_employees) + assert a4.task1_older.equals(a4.task2_employees) test2_json_df = pd.DataFrame({ 'Name': ['Eve', 'Frank'], 'Age': [28, 40], @@ -35,22 +35,22 @@ def test_read_data_frame_from_csv(): def test_read_data_frame_from_json(): assert os.access("./additional_employees.json", os.F_OK) == True - assert a3.json_employees.equals(test2_json_df) + assert a4.json_employees.equals(test2_json_df) def test_concat_json_employees(): - assert a3.more_employees.equals(pd.concat([a3.task2_employees, a3.json_employees], ignore_index=True)) - assert a3.more_employees.shape == (5, 4) + assert a4.more_employees.equals(pd.concat([a4.task2_employees, a4.json_employees], ignore_index=True)) + assert a4.more_employees.shape == (5, 4) # Task 3 def test_head(): - assert a3.first_three.equals(a3.more_employees.head(3)) + assert a4.first_three.equals(a4.more_employees.head(3)) def test_tail(): - assert a3.last_two.equals(a3.more_employees.tail(2)) + assert a4.last_two.equals(a4.more_employees.tail(2)) def test_shape(): - assert a3.employee_shape == (5, 4) + assert a4.employee_shape == (5, 4) # Task 4 @@ -78,35 +78,35 @@ def test_shape(): tdf['Department'] = tdf['Department'].str.strip().str.upper() def test_dirty_data_read(): - assert a3.dirty_data.equals(ddf) + assert a4.dirty_data.equals(ddf) def test_no_duplicate_rows(): - assert len(a3.clean_data) == 6 + assert len(a4.clean_data) == 6 def test_age_numeric(): - assert pd.api.types.is_numeric_dtype(a3.clean_data['Age']) - assert a3.clean_data['Age'].dropna().between(1, 100).all() + assert pd.api.types.is_numeric_dtype(a4.clean_data['Age']) + assert a4.clean_data['Age'].dropna().between(1, 100).all() def test_salary_numeric(): - assert pd.api.types.is_numeric_dtype(a3.clean_data['Salary']) + assert pd.api.types.is_numeric_dtype(a4.clean_data['Salary']) def test_no_missing_age_or_salary(): - assert not a3.clean_data['Age'].isnull().any() - assert not a3.clean_data['Salary'].isnull().any() + assert not a4.clean_data['Age'].isnull().any() + assert not a4.clean_data['Salary'].isnull().any() def test_hire_date_datetime(): - assert pd.api.types.is_datetime64_any_dtype(a3.clean_data['Hire Date']) + assert pd.api.types.is_datetime64_any_dtype(a4.clean_data['Hire Date']) def test_department_uppercase(): all_upper = True - for dept in a3.clean_data['Department']: + for dept in a4.clean_data['Department']: if not dept.isupper(): all_upper = False assert all_upper # April 2: If dates are not converted properly with form="mixed" will end up with NaTs def test_hire_date_notNAT(): - nat_count = a3.clean_data['Hire Date'].isna().sum() + nat_count = a4.clean_data['Hire Date'].isna().sum() assert nat_count == 0 diff --git a/assignment3/assignment3.py b/assignment4/assignment4.py similarity index 100% rename from assignment3/assignment3.py rename to assignment4/assignment4.py diff --git a/assignment3/dirty_data.csv b/assignment4/dirty_data.csv similarity index 100% rename from assignment3/dirty_data.csv rename to assignment4/dirty_data.csv From 203c878a6231b18be48a857da0acca8ec6fff475 Mon Sep 17 00:00:00 2001 From: Tom Arns Date: Fri, 25 Jul 2025 22:11:52 -0700 Subject: [PATCH 25/27] renamed more folders for 12 to 3 renumbering --- {assignment12 => assignment3}/.keep | 0 assignment7/.keep | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {assignment12 => assignment3}/.keep (100%) delete mode 100644 assignment7/.keep diff --git a/assignment12/.keep b/assignment3/.keep similarity index 100% rename from assignment12/.keep rename to assignment3/.keep diff --git a/assignment7/.keep b/assignment7/.keep deleted file mode 100644 index e69de29..0000000 From 50b213567d6ea081e9c8eb491d5f3e3eb2401348 Mon Sep 17 00:00:00 2001 From: Ricardo Santiz Date: Tue, 28 Apr 2026 17:20:13 -0700 Subject: [PATCH 26/27] Complete Lesson 3: Decorators, Closures, and Classes --- assignment3/decorator.log | 15 +++++++++++++ assignment3/developer-class.py | 15 +++++++++++++ assignment3/employee-class.py | 16 ++++++++++++++ assignment3/hangman-closure.py | 25 ++++++++++++++++++++++ assignment3/list-comprehensions.py | 12 +++++++++++ assignment3/log-decorator.py | 34 ++++++++++++++++++++++++++++++ assignment3/type-decorator.py | 21 ++++++++++++++++++ 7 files changed, 138 insertions(+) create mode 100644 assignment3/decorator.log create mode 100644 assignment3/developer-class.py create mode 100644 assignment3/employee-class.py create mode 100644 assignment3/hangman-closure.py create mode 100644 assignment3/list-comprehensions.py create mode 100644 assignment3/log-decorator.py create mode 100644 assignment3/type-decorator.py diff --git a/assignment3/decorator.log b/assignment3/decorator.log new file mode 100644 index 0000000..3a29aee --- /dev/null +++ b/assignment3/decorator.log @@ -0,0 +1,15 @@ +function: task_1a +positional parameters: none +keyword parameters: none +return: None + +function: task_1b +positional parameters: [10, 20] +keyword parameters: none +return: True + +function: task_1c +positional parameters: none +keyword parameters: {'user': 'Ricardo', 'status': 'Student'} +return: logger_decorator + diff --git a/assignment3/developer-class.py b/assignment3/developer-class.py new file mode 100644 index 0000000..746ed2a --- /dev/null +++ b/assignment3/developer-class.py @@ -0,0 +1,15 @@ +class Employee: + def __init__(self, first, last, salary): + self.first = first + self.last = last + self.salary = float(salary) + +class Developer(Employee): + def __init__(self, first, last, salary, prog_lang): + super().__init__(first, last, salary) + self.prog_lang = prog_lang + +dev_1 = Developer("Ricardo", "Santiz", 60000, "Python") +print(f"Name: {dev_1.first} {dev_1.last}") +print(f"Language: {dev_1.prog_lang}") +print(f"Salary: {dev_1.salary}") \ No newline at end of file diff --git a/assignment3/employee-class.py b/assignment3/employee-class.py new file mode 100644 index 0000000..aa48b5d --- /dev/null +++ b/assignment3/employee-class.py @@ -0,0 +1,16 @@ + +class Employee: + def __init__(self, first, last, salary): + self.first = first + self.last = last + self.salary = float(salary) + self.email = f"{first.lower()}.{last.lower()}@company.com" + + def give_raise(self, amount): + self.salary += amount + +emp_1 = Employee("Ricardo", "Santiz", 50000) +print(emp_1.email) +print(f"Old Salary: {emp_1.salary}") +emp_1.give_raise(5555) +print(f"New Salary: {emp_1.salary}") diff --git a/assignment3/hangman-closure.py b/assignment3/hangman-closure.py new file mode 100644 index 0000000..4577aca --- /dev/null +++ b/assignment3/hangman-closure.py @@ -0,0 +1,25 @@ +def hangman_game(word): + word = word.lower() + guessed_letters = [] + + def guess(letter): + letter = letter.lower() + if letter in guessed_letters: + return f"You already guessed '{letter}'." + + guessed_letters.append(letter) + + display_word = [char if char in guessed_letters else "_" for char in word] + + if letter in word: + return f"Correct! {' '.join(display_word)}" + else: + return f"Incorrect. {' '.join(display_word)}" + + return guess + +play = hangman_game("Python") +print(play("p")) +print(play("y")) +print(play("z")) +print(play("p")) diff --git a/assignment3/list-comprehensions.py b/assignment3/list-comprehensions.py new file mode 100644 index 0000000..29dd0da --- /dev/null +++ b/assignment3/list-comprehensions.py @@ -0,0 +1,12 @@ +import csv + +with open('csv/employees.csv', 'r') as file: + reader = csv.reader(file) + data = list(reader) + + +full_names = [f"{row[0]} {row[1]}" for row in data[1:]] +print(full_names) + +names_with_e = [name for name in full_names if 'e' in name.lower()] +print(names_with_e) \ No newline at end of file diff --git a/assignment3/log-decorator.py b/assignment3/log-decorator.py new file mode 100644 index 0000000..dd5b90a --- /dev/null +++ b/assignment3/log-decorator.py @@ -0,0 +1,34 @@ +import logging +logger = logging.getLogger(__name__ + "_parameter_log") +logger.setLevel(logging.INFO) +logger.addHandler(logging.FileHandler("./assignment3/decorator.log","a")) + +def logger_decorator(func): + def wrapper(*args, **kwargs): + pos_params = list(args) if args else "none" + kw_params = kwargs if kwargs else "none" + result = func(*args, **kwargs) + + log_msg = (f"function: {func.__name__}\n" + f"positional parameters: {pos_params}\n" + f"keyword parameters: {kw_params}\n" + f"return: {result}\n") + logger.info(log_msg) + return result + return wrapper + +@logger_decorator +def task_1a(): + print("Hello, World!") + +@logger_decorator +def task_1b(*args): + return True + +@logger_decorator +def task_1c(**kwargs): + return "logger_decorator" + +task_1a() +task_1b(10, 20) +task_1c(user="Ricardo", status="Student") diff --git a/assignment3/type-decorator.py b/assignment3/type-decorator.py new file mode 100644 index 0000000..8c14d41 --- /dev/null +++ b/assignment3/type-decorator.py @@ -0,0 +1,21 @@ +def type_converter(type_of_output): + def decorator(func): + def wrapper(*args, **kwargs): + value = func(*args, **kwargs) + return type_of_output(value) + return wrapper + return decorator + +@type_converter(str) +def return_int(): + return 5 + +@type_converter(int) +def return_string_num(): + return "123" + +string_five = return_int() +int_one_two_three = return_string_num() + +print(f"Value: {string_five}, Type: {type(string_five).__name__}") +print(f"Value: {int_one_two_three}, Type: {type(int_one_two_three).__name__}") From 1e20ab25f1f93369df96d38c7b01a74374029cd0 Mon Sep 17 00:00:00 2001 From: Ricardo Santiz Date: Sun, 14 Jun 2026 20:02:01 -0700 Subject: [PATCH 27/27] Complete Assignment 10 Advanced SQL --- assignment10/advanced_sql.py | 119 +++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 assignment10/advanced_sql.py diff --git a/assignment10/advanced_sql.py b/assignment10/advanced_sql.py new file mode 100644 index 0000000..1f9240c --- /dev/null +++ b/assignment10/advanced_sql.py @@ -0,0 +1,119 @@ +import sqlite3 + +try: + with sqlite3.connect("../db/lesson.db") as conn: + conn.execute("PRAGMA foreign_keys = 1") + cursor = conn.cursor() + + # Task 1: Complex JOINs with aggregation + query = """ + SELECT orders.order_id, + SUM(products.price * line_items.quantity) AS total_price + FROM orders + JOIN line_items ON orders.order_id = line_items.order_id + JOIN products ON line_items.product_id = products.product_id + GROUP BY orders.order_id + ORDER BY orders.order_id + LIMIT 5 + """ + cursor.execute(query) + print("Task 1 Results:") + for row in cursor.fetchall(): + print(row) + + # Task 2: Subquery for average customer order price + query = """ + SELECT customers.customer_name, + AVG(order_totals.total_price) AS average_total_price + FROM customers + LEFT JOIN + ( + SELECT orders.customer_id AS customer_id_b, + SUM(products.price * line_items.quantity) AS total_price + FROM orders + JOIN line_items ON orders.order_id = line_items.order_id + JOIN products ON line_items.product_id = products.product_id + GROUP BY orders.order_id + ) AS order_totals + ON customers.customer_id = order_totals.customer_id_b + GROUP BY customers.customer_id + """ + cursor.execute(query) + print("\nTask 2 Results:") + for row in cursor.fetchall(): + print(row) + + # Task 3: Insert new order with transaction + cursor.execute(""" + SELECT customer_id + FROM customers + WHERE customer_name = 'Perez and Sons' + """) + customer_id = cursor.fetchone()[0] + + cursor.execute(""" + SELECT employee_id + FROM employees + WHERE first_name = 'Miranda' + AND last_name = 'Harris' + """) + employee_id = cursor.fetchone()[0] + + cursor.execute(""" + SELECT product_id + FROM products + ORDER BY price + LIMIT 5 + """) + products = cursor.fetchall() + + cursor.execute(""" + INSERT INTO orders (customer_id, employee_id) + VALUES (?, ?) + RETURNING order_id + """, (customer_id, employee_id)) + + order_id = cursor.fetchone()[0] + + for product in products: + product_id = product[0] + cursor.execute(""" + INSERT INTO line_items (order_id, product_id, quantity) + VALUES (?, ?, ?) + """, (order_id, product_id, 10)) + + conn.commit() + + cursor.execute(""" + SELECT line_items.line_item_id, + line_items.quantity, + products.product_name + FROM line_items + JOIN products ON line_items.product_id = products.product_id + WHERE line_items.order_id = ? + """, (order_id,)) + + print("\nTask 3 Results:") + for row in cursor.fetchall(): + print(row) + + # Task 4: Aggregation with HAVING + query = """ + SELECT employees.employee_id, + employees.first_name, + employees.last_name, + COUNT(orders.order_id) AS order_count + FROM employees + JOIN orders ON employees.employee_id = orders.employee_id + GROUP BY employees.employee_id + HAVING COUNT(orders.order_id) > 5 + """ + cursor.execute(query) + + print("\nTask 4 Results:") + for row in cursor.fetchall(): + print(row) + +except sqlite3.Error as e: + print("Database error:", e) +