8000 Fixed tests. (#223) · shri-empa/python-tutorial@dfe2bba · GitHub
[go: up one dir, main page]

Skip to content

Commit dfe2bba

Browse files
baffellidespadam
andauthored
Fixed tests. (empa-scientific-it#223)
* Fixed tests. * Improved wording of exercise * Update input_output.ipynb Co-authored-by: Despina Adamopoulou <16343312+despadam@users.noreply.github.com> * Fixed test for print_odd exercise * Fixed error message * Fixed another misleading error message * Fixed TOC. * updating TOC and titles for exercise sections --------- Co-authored-by: Despina Adamopoulou <16343312+despadam@users.noreply.github.com> Co-authored-by: Despina Adamopoulou <despoina.adamopoulou@empa.ch>
1 parent 5442f1a commit dfe2bba

File tree

3 files changed

+91
-66
lines changed

3 files changed

+91
-66
lines changed

input_output.ipynb

Lines changed: 56 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,30 @@
55
"cell_type": "markdown",
66
"metadata": {},
77
"source": [
8-
"## Table of contents\n",
9-
"\n",
10-
"- [String input](#String-input)\n",
11-
"- [File I/O](#File-I/O)\n",
12-
"- [Writing to a file](#Writing-to-a-file)\n",
13-
"- [Context managers](#Context-managers)\n",
14-
"- [Binary I/O](#Binary-I/O)\n",
15-
" - [Bytes and strings](#Bytes-and-strings)\n",
16-
" - [Converting bytes to text](#Converting-bytes-to-text)\n",
17-
"- [Reading/Writing CSV files](#Reading/Writing-CSV-files)\n",
18-
"- [Exercises](#Exercises)\n",
8+
"# Table of Contents\n",
9+
" - [References](#References)\n",
10+
" - [Introduction](#Introduction)\n",
11+
" - [String input and output ](#String-input-and-output)\n",
12+
" - [String output](#String-output)\n",
13+
" - [String input](#String-input)\n",
14+
" - [Warm-up exercises](#Warm-up-exercises)\n",
15+
" - [File I/O](#File-I/O)\n",
16+
" - [Paths](#Paths)\n",
17+
" - [Exercises on Paths](#Exercises-on-Paths)\n",
18+
" - [Reading from a file](#Reading-from-a-file)\n",
19+
" - [Writing to a file](#Writing-to-a-file)\n",
20+
" - [Exercises on file reading and writing](#Exercises-on-file-reading-and-writing)\n",
21+
" - [Context managers](#Context-managers)\n",
22+
" - [Binary I/O](#Binary-I/O)\n",
23+
" - [Bytes and strings](#Bytes-and-strings)\n",
24+
" - [Converting bytes to text ](#Converting-bytes-to-text)\n",
25+
" - [Reading/Writing CSV files](#Reading/Writing-CSV-files)\n",
26+
" - [Exercises](#Exercises)\n",
1927
" - [Exercise 1: CSV to dictionary 🌶️🌶️](#Exercise-1:-CSV-to-dictionary-🌶️🌶️)\n",
2028
" - [Exercise 2: Counting words 🌶️](#Exercise-2:-Counting-words-🌶️)\n",
29+
" - [Exercise 3: Letter statistics 🌶️🌶️](#Exercise-3:-Letter-statistics-🌶️🌶️)\n",
2130
" - [Exercise 4: Translating words 🌶️🌶️](#Exercise-4:-Translating-words-🌶️🌶️)\n",
22-
" - [Exercise 5: Binary format 🌶️🌶️🌶️](#Exercise-5:-Binary-format-🌶️🌶️🌶️)\n"
31+
" - [Exercise 5: Binary format 🌶️🌶️🌶️](#Exercise-5:-Binary-format-🌶️🌶️🌶️)"
2332
]
2433
},
2534
{
@@ -120,7 +129,7 @@
120129
"cell_type": "markdown",
121130
"metadata": {},
122131
"source": [
123-
"### Exercises"
132+
"### Warm-up exercises"
124133
]
125134
},
126135
{
@@ -356,7 +365,7 @@
356365
"cell_type": "markdown",
357366
"metadata": {},
358367
"source": [
359-
"### Exercises"
368+
"### Exercises on Paths"
360369
]
361370
},
362371
{
@@ -505,37 +514,6 @@
505514
"This is the most *pythonic* way to read a file line-by-line instead of reading the full contents at once."
506515
]
507516
},
508-
{
509-
"attachments": {},
510-
"cell_type": "markdown",
511-
"metadata": {},
512-
"source": [
513-
"### Exercises"
514-
]
515-
},
516-
{
517-
"attachments": {},
518-
"cell_type": "markdown",
519-
"metadata": {},
520-
"source": [
521-
"1. Modify the function `solution_read_file` to return the content of the file passed as the `input_file` argument. Return the content as a **list of strings**, one string per line.\n"
522-
]
523-
},
524-
{
525-
"cell_type": "code",
526-
"execution_count": null,
527-
"metadata": {},
528-
"outputs": [],
529-
"source": [
530-
"%%ipytest\n",
531-
"\n",
532-
"from pathlib import Path\n",
533-
"\n",
534-
"def solution_read_file(input_file: Path) -> \"list[str]\": \n",
535-
" \"\"\"Write your solution here\"\"\"\n",
536-
" pass"
537-
]
538-
},
539517
{
540518
"attachments": {},
541519
"cell_type": "markdown",
@@ -605,7 +583,7 @@
605583
"cell_type": "markdown",
606584
"metadata": {},
607585
"source": [
608-
"### Exercises"
586+
"### Exercises on file reading and writing"
609587
]
610588
},
611589
{
@@ -622,7 +600,30 @@
622600
"cell_type": "markdown",
623601
"metadata": {},
624602
"source": [
625-
"1. Modify the function `solution_write_file` to write the sentence \"python tutorial 2023\" (**without quotes**) to the file `output_file`, which is available as a `Path` object as argument to the function."
603+
"1. Modify the function `solution_read_file` to return the content of the file passed as the `input_file` argument. Return the content as a **list of strings**, one string per line.\n"
604+
]
605+
},
606+
{
607+
"cell_type": "code",
608+
"execution_count": null,
609+
"metadata": {},
610+
"outputs": [],
611+
"source": [
612+
"%%ipytest\n",
613+
"\n",
614+
"from pathlib import Path\n",
615+
"\n",
616+
"def solution_read_file(input_file: Path) -> \"list[str]\": \n",
617+
" \"\"\"Write your solution here\"\"\"\n",
618+
" pass"
619+
]
620+
},
621+
{
622+
"attachments": {},
623+
"cell_type": "markdown",
624+
"metadata": {},
625+
"source": [
626+
"2. Modify the function `solution_write_file` to write the sentence \"python tutorial 2023\" (**without quotes**) to the file `output_file`, which is available as a `Path` object as argument to the function."
626627
]
627628
},
628629
{
@@ -647,7 +648,7 @@
647648
"cell_type": "markdown",
648649
"metadata": {},
649650
"source": [
650-
"1. Modify the function `solution_read_write_file` to read the lines from the file `input_file` and write them in the form `line, length`, to the file `output_file`. Here `line` is the line of text in `input_file` **without the line ending**, `length` is **number of characters** in that line.\n",
651+
"3. Modify the function `solution_read_write_file` to read the lines from the file `input_file` and write them in the form `line, length`, to the file `output_file`. Here `line` is the line of text in `input_file` **without the line ending**, `length` is **number of characters** in that line.\n",
651652
"If `input_file` contains these lines:\n",
652653
" ```\n",
653654
" first\n",
@@ -1104,7 +1105,7 @@
11041105
"tags": []
11051106
},
11061107
"source": [
1107-
"Write a function to read all the lines from [`lines.txt`](./tutorial/tests/data/lines.txt) and count the number of words in the file. The solution should be a single number.\n",
1108+
"Write a function to read all the lines from `input_file` and count the number of words in the file. The solution should be a single number.\n",
11081109
"\n",
11091110
"For example, for the file\n",
11101111
"```\n",
@@ -1118,7 +1119,11 @@
11181119
"\n",
11191120
"<div class=\"alert alert-block alert-info\">\n",
11201121
" <h4><b>Hint</b></h4>\n",
1121-
" The file is available as the parameter <code>input_file</code> of <code>solution_exercise2</code> function\n",
1122+
" <ul>\n",
1123+
" <li>The file is available as the parameter <code>input_file</code> of <code>solution_exercise2</code> function</li>\n",
1124+
" <li>A word consists of printable characters without line ends and spaces</li>\n",
1125+
" </ul>\n",
1126+
" \n",
11221127
"</div>\n",
11231128
"\n",
11241129
"\n"
@@ -1338,7 +1343,7 @@
13381343
"name": "python",
13391344
"nbconvert_exporter": "python",
13401345
"pygments_lexer": "ipython3",
1341-
"version": "3.11.4"
1346+
"version": "3.10.14"
13421347
},
13431348
"vscode": {
13441349
"interpreter": {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
this file has
2+
more words in each
3+
line
4+
but it is shorter I think
5+
I hope you have fun solving this exercise
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,24 @@ def get_data(name: str, data_dir: str = "data") -> pl.Path:
1515
return (pl.Path.cwd() / f"tutorial/tests/{data_dir}/{name}").resolve()
1616

1717

18-
def reference_print_odd(num: int) -> None:
19-
for i in range(num):
18+
def reference_print_odd(n: int) -> None:
19+
for i in range(n):
2020
if i % 2 != 0:
2121
print(i)
2222

2323

24-
@pytest.mark.parametrize("num", [1, 2, 3, 4, 5])
25-
def test_print_odd(function_to_test, num: int):
24+
@pytest.mark.parametrize("n", [1, 2, 3, 4, 5])
25+
def test_print_odd(function_to_test, n: int):
2626
with StringIO() as solution_stdout, StringIO() as reference_stdout:
2727
with contextlib.redirect_stdout(solution_stdout):
28-
function_to_test(num)
28+
function_to_test(n)
29+
solution_text = solution_stdout.getvalue()
2930

3031
with contextlib.redirect_stdout(reference_stdout):
31-
reference_print_odd(num)
32+
reference_print_odd(n)
33+
reference_text = reference_stdout.getvalue()
3234

33-
assert reference_stdout.getvalue() == solution_stdout.getvalue()
35+
assert solution_text == reference_text
3436

3537

3638
def reference_find_all_files(f: pl.Path) -> List[pl.Path]:
@@ -73,16 +75,26 @@ def test_write_file(function_to_test, tmp_path: pl.Path):
7375
function_to_test(tmp_user)
7476
reference_write_file(tmp_test)
7577

76-
if not tmp_user.exists():
77-
pytest.fail("Cannot read from inexistent file.")
78+
assert (
79+
tmp_user.exists()
80+
), """The file was not created. Make sure to create the file in the function. Hint: use `open(output_file, "w")`"""
7881

79-
assert tmp_user.read_text() == tmp_test.read_text()
82+
assert (
83+
tmp_user.read_text() == tmp_test.read_text()
84< 1241 code class="diff-text syntax-highlighted-line addition">+
), "The file content is not correct."
8085

8186

8287
def reference_read_write_file(input_file: pl.Path, output_file: pl.Path) -> None:
88+
# We open the input and output file at the same time
8389
with input_file.open("r") as read_file, output_file.open("w") as write_file:
90+
# Here we iterate over each line of the input file
8491
for line in read_file.readlines():
85-
write_file.write("{}, {}\n".format(line.strip("\n\r"), len(line)))
92+
# We remove line breaks and write the line to the output file
93+
clean_line = line.strip("\n\r")
94+
# We crete the output line
95+
output_line = f"{clean_line}, {len(clean_line)}\n"
96+
# Finally we write the line and its length to the output file
97+
write_file.write(output_line)
8698

8799

88100
def test_read_write_file(function_to_test, tmp_path: pl.Path):
@@ -92,6 +104,7 @@ def test_read_write_file(function_to_test, tmp_path: pl.Path):
92104

93105
function_to_test(input_file, output_file)
94106
reference_read_write_file(input_file, test_output_file)
107+
assert output_file.exists(), "The output file was not created."
95108

96109
assert output_file.read_text() == test_output_file.read_text()
97110

@@ -105,8 +118,9 @@ def reference_exercise1(file: pl.Path) -> Dict[str, List[str]]:
105118
}
106119

107120

108-
def test_exercise1(function_to_test):
109-
f = get_data("example.csv")
121+
@pytest.mark.parametrize("file", ["example.csv"])
122+
def test_exercise1(function_to_test, file: str):
123+
f = get_data(file)
110124
assert function_to_test(f) == reference_exercise1(f)
111125

112126

@@ -121,8 +135,9 @@ def reference_exercise2(file: pl.Path) -> int:
121135
)
122136

123137

124-
def test_exercise2(function_to_test):
125-
f = get_data("lines.txt")
138+
@pytest.mark.parametrize("file", ["lines.txt", "lines2.txt"])
139+
def test_exercise2(function_to_test, file: str):
140+
f = get_data(file)
126141
assert function_to_test(f) == reference_exercise2(f)
127142

128143