{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "# ZHUDDLE | Chapter 07: Files\n\n8 coding missions + 10 MCQs. 100 XP.\n\nAdapted from Charles R. Severance, Python for Everybody (CC BY 4.0).\n\nSource: https://www.py4e.com/html3/07-files\n\nReading: https://www.py4e.com/html3/07-files\n\nThe browser runs five independent cases per coding mission. This notebook supplies the first sample; input prompts here are interactive.",
      "id": "files-000"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## C01 | Count lines in a file\n\nOpen the supplied practice file `sample.txt`. Use a for loop over its handle to count lines into `count`, then print count. A final line without a newline still counts.\n\nFive independent checks are worth 2 XP each. \n\nPractice files are created afresh for every check. Sample file contents:\n\n**sample.txt**\n```text\nHello\nWorld!\n\n```\n\n**Source checkpoint:** Opening files; Reading files",
      "id": "files-001"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "\n# Practice fixture supplied by ZHUDDLE\nwith open('sample.txt', \"w\") as fixture:\n    fixture.write('Hello\\nWorld!\\n')\n",
      "execution_count": null,
      "outputs": [],
      "id": "files-002"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "count = 0\n# Open sample.txt and count its lines.",
      "execution_count": null,
      "outputs": [],
      "id": "files-003"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## C02 | Read and exhaust a handle\n\nOpen `sample.txt`. Save the first call to its read method in `contents`, and the second call on the same handle in `again`. Save the character count of contents as `length`. Close the handle.\n\nFive independent checks are worth 2 XP each. \n\nPractice files are created afresh for every check. Sample file contents:\n\n**sample.txt**\n```text\nHello\nWorld!\n\n```\n\n**Source checkpoint:** Reading files",
      "id": "files-004"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "\n# Practice fixture supplied by ZHUDDLE\nwith open('sample.txt', \"w\") as fixture:\n    fixture.write('Hello\\nWorld!\\n')\n",
      "execution_count": null,
      "outputs": [],
      "id": "files-005"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "# Read the same handle twice.",
      "execution_count": null,
      "outputs": [],
      "id": "files-006"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## C03 | Select sender headers\n\nRead `mail.txt` line by line. Print only lines beginning with `From:`. Strip trailing whitespace before printing so no extra blank lines appear.\n\nFive independent checks are worth 2 XP each. \n\nPractice files are created afresh for every check. Sample file contents:\n\n**mail.txt**\n```text\nFrom: ada@example.org\nSubject: Hello\n\nFrom: lin@example.org\n\n```\n\n**Source checkpoint:** Searching through a file",
      "id": "files-007"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "\n# Practice fixture supplied by ZHUDDLE\nwith open('mail.txt', \"w\") as fixture:\n    fixture.write('From: ada@example.org\\nSubject: Hello\\n\\nFrom: lin@example.org\\n')\n",
      "execution_count": null,
      "outputs": [],
      "id": "files-008"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "# Filter From: headers.",
      "execution_count": null,
      "outputs": [],
      "id": "files-009"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## C04 | Search anywhere in a line\n\nRead `mail.txt`. Use find to print lines containing `@uct.ac.za` anywhere. Remove trailing whitespace and print each matching line once.\n\nFive independent checks are worth 2 XP each. \n\nPractice files are created afresh for every check. Sample file contents:\n\n**mail.txt**\n```text\nFrom: a@uct.ac.za\nFrom: b@example.org\n\n```\n\n**Source checkpoint:** Searching through a file",
      "id": "files-010"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "\n# Practice fixture supplied by ZHUDDLE\nwith open('mail.txt', \"w\") as fixture:\n    fixture.write('From: a@uct.ac.za\\nFrom: b@example.org\\n')\n",
      "execution_count": null,
      "outputs": [],
      "id": "files-011"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "# Find the requested domain in each line.",
      "execution_count": null,
      "outputs": [],
      "id": "files-012"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## C05 | Choose a file safely\n\nRead a filename with input. Try to open it, count lines beginning with `Subject:`, and print only that count. If opening fails, print `File cannot be opened:` followed by the filename. Use try/except and avoid reading a handle that failed to open.\n\nFive independent checks are worth 2 XP each. \n\nUse `input()` normally: the checker enters test values for you. Sample inputs, in order: `mail.txt`. Input prompts are omitted from captured output.\n\nPractice files are created afresh for every check. Sample file contents:\n\n**mail.txt**\n```text\nSubject: one\nFrom: a\nSubject: two\n\n```\n\n**Source checkpoint:** Letting the user choose the file name; Using try, except, and open",
      "id": "files-013"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "\n# Practice fixture supplied by ZHUDDLE\nwith open('mail.txt', \"w\") as fixture:\n    fixture.write('Subject: one\\nFrom: a\\nSubject: two\\n')\n",
      "execution_count": null,
      "outputs": [],
      "id": "files-014"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "# Read the filename; handle missing files.",
      "execution_count": null,
      "outputs": [],
      "id": "files-015"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## C06 | Uppercase a file\n\nAsk for a filename using input, open it, and print every line in uppercase. Remove trailing whitespace before printing. Test files exist, so this mission does not require missing-file handling.\n\nFive independent checks are worth 2 XP each. \n\nUse `input()` normally: the checker enters test values for you. Sample inputs, in order: `words.txt`. Input prompts are omitted from captured output.\n\nPractice files are created afresh for every check. Sample file contents:\n\n**words.txt**\n```text\nhello\nworld\n\n```\n\n**Source checkpoint:** Exercises: Exercise 1",
      "id": "files-016"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "\n# Practice fixture supplied by ZHUDDLE\nwith open('words.txt', \"w\") as fixture:\n    fixture.write('hello\\nworld\\n')\n",
      "execution_count": null,
      "outputs": [],
      "id": "files-017"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "# Open the requested file and uppercase each line.",
      "execution_count": null,
      "outputs": [],
      "id": "files-018"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## C07 | Average spam confidence\n\nOpen `mail.txt`, select `X-DSPAM-Confidence:` lines, and convert the part after the colon to float. Track `count` and `total`, then print the average. Print `No matching lines` if count is zero. Values in matching lines are valid numbers.\n\nFive independent checks are worth 2 XP each. \n\nPractice files are created afresh for every check. Sample file contents:\n\n**mail.txt**\n```text\nX-DSPAM-Confidence: 0.5\nIgnore this\nX-DSPAM-Confidence: 1.0\n\n```\n\n**Source checkpoint:** Exercises: Exercise 2",
      "id": "files-019"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "\n# Practice fixture supplied by ZHUDDLE\nwith open('mail.txt', \"w\") as fixture:\n    fixture.write('X-DSPAM-Confidence: 0.5\\nIgnore this\\nX-DSPAM-Confidence: 1.0\\n')\n",
      "execution_count": null,
      "outputs": [],
      "id": "files-020"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "count = 0\ntotal = 0.0\n# Read matching lines, then calculate the average.",
      "execution_count": null,
      "outputs": [],
      "id": "files-021"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## C08 | Write a fresh text file\n\nOpen `output.txt` in write mode. Write supplied `first` and `second` on separate lines, each ending with a newline. Close the handle. Existing file contents must be replaced.\n\nFive independent checks are worth 2 XP each. The checker supplies the variables below with different values on each check. Use them without replacing their starting values.\n\n```python\nfirst = 'Hello'\nsecond = 'World'\n```\n\nPractice files are created afresh for every check. Sample file contents:\n\n**output.txt**\n```text\nold contents that must disappear\n\n```\n\n**Source checkpoint:** Writing files",
      "id": "files-022"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "first = 'Hello'\nsecond = 'World'\n# Practice fixture supplied by ZHUDDLE\nwith open('output.txt', \"w\") as fixture:\n    fixture.write('old contents that must disappear\\n')\n",
      "execution_count": null,
      "outputs": [],
      "id": "files-023"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "# Write two lines to output.txt.",
      "execution_count": null,
      "outputs": [],
      "id": "files-024"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M01 | A file handle\n\nWhat does open return when it succeeds?\n\nA. All file text\nB. A file handle\nC. The line count\nD. A list of words",
      "id": "files-025"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m01 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-026"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M02 | Missing file\n\nOpening a missing file for reading normally raises which exception?\n\nA. TypeError\nB. ZeroDivisionError\nC. FileNotFoundError\nD. No exception",
      "id": "files-027"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m02 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-028"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M03 | Newline length\n\nHow many characters are in the string `\"X\nY\"`?\n\nA. 2\nB. 4\nC. 5\nD. 3",
      "id": "files-029"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m03 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-030"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M04 | File iteration\n\nA for loop over a text file handle yields what?\n\nA. One line at a time\nB. The entire file each time\nC. Only filenames\nD. One integer per byte",
      "id": "files-031"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m04 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-032"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M05 | Read again\n\nAfter f.read() reaches the end, what does another f.read() return?\n\nA. The whole file again\nB. None\nC. An empty string\nD. The last line",
      "id": "files-033"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m05 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-034"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M06 | Double spacing\n\nWhy can print(line) show blank lines between file lines?\n\nA. Files add tabs\nB. line already ends in a newline and print adds another\nC. print repeats each word\nD. open inserts blank lines",
      "id": "files-035"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m06 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-036"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M07 | Prefix filtering\n\nWhich checks whether line begins with `From:`?\n\nA. line.find(\"From:\") == -1\nB. \"From:\" == line\nC. line.upper()\nD. line.startswith(\"From:\")",
      "id": "files-037"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m07 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-038"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M08 | Choosing a filename\n\nWhy read a filename with input?\n\nA. To process different files without editing the code\nB. To create every missing file\nC. To avoid opening the file\nD. To load every file at once",
      "id": "files-039"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m08 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-040"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M09 | Write mode\n\nWhat happens when an existing file is opened with mode w?\n\nA. New text always appends\nB. The file is read only\nC. Its old contents are cleared\nD. Nothing until close",
      "id": "files-041"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m09 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-042"
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": "## M10 | Write return value\n\nWhat does a text file handle write method return?\n\nA. The file handle\nB. The number of characters written\nC. The whole file\nD. Always None",
      "id": "files-043"
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": "m10 = \"\"  # A, B, C, or D",
      "execution_count": null,
      "outputs": [],
      "id": "files-044"
    }
  ]
}
