LambdaLabTM
Computer Science · Class 12 Project · Subject Code 083
Sample ProjectPython File Handling⏱️ 12 min read

Question Paper Generator

Build a unit test from a question bank, following a blueprint of chapters and marks.

1Introduction: the problem it solves

A teacher setting a unit test opens last year's paper, changes a few questions and hopes the marks add up. Doing it properly means picking questions by chapter and by mark weight, which is slow enough that it usually is not done properly.

If the questions live in a file with their chapter and marks attached, a program can follow the blueprint exactly and produce a different paper every time.

who would use it

Any teacher, a coaching centre, or a school setting multiple sets of the same paper.

Why it is worth computerising

Setting a unit test properly means choosing questions to a blueprint — so many of one mark from this chapter, so many of five from that one — and checking that the total comes out right. Doing this by hand is slow enough that most teachers instead edit last year's paper, which is how the same questions come round year after year.

A question bank stored with each question's chapter and mark value turns paper-setting into selection rather than searching. The blueprint is followed exactly, the marks are added from the paper itself so they cannot disagree with it, and because the choice is random, two sets of the same test can be produced for two halves of a room.

Objectives

  1. To keep every question in one bank, tagged with its chapter and mark value
  2. To build a paper from a blueprint of chapters and marks rather than by hand
  3. To pick questions at random so two sets of the same paper differ
  4. To guarantee no question is repeated within one paper
  5. To total the marks from the paper itself, so the total cannot disagree with it

2How the job is done today

Before writing anything it is worth asking how the work is handled at present, and why each of those answers falls short. These were examined:

Last year's paper, edited

The honest answer for most unit tests. It is fast, and it drifts — the same questions return year after year and the blueprint is never really checked.

Online test generators

Good, and built around their own question banks. A teacher's own questions have to be entered into somebody else's system first.

Question bank books

Plenty of questions, no blueprint. Selecting and balancing them is still done by hand, which is the slow part.

3Functionalities

  • Keeps every question in a bank file with its chapter and mark value
  • Sorts the bank into chapter and marks buckets when it loads
  • Takes a blueprint — how many questions of each chapter and mark value
  • Picks at random, so two sets of the same paper differ
  • Warns instead of failing when the bank does not have enough questions
  • Adds up the total marks and writes the paper to a file

The functions that provide them

FunctionArgumentsWhat it does
load_bank()Read the bank and sort the questions into chapter -> marks buckets.
build_paper()bank, plan, seed=Noneplan is a list of (chapter, marks, how_many).
write_paper()paper, filenameWrite the paper out, numbered, and return its total marks.

4Technical details

LanguagePython 3
StoragePlain text and CSV files
Modules used
  • csv — the question bank, which a teacher can extend in a spreadsheet
  • random — random.sample() picks without repeating a question
  • Text file handling — the finished paper is written out

5How the data is stored

`questions.csv` is the bank: chapter, marks and the question text. The blueprint is a list of (chapter, marks, how many) in the program. Passing a seed makes a paper reproducible, which matters when you need to print the same set twice.

questions.csv — the question bank

FieldTypeDescription
chaptertextChapter the question belongs to
marksintegerMark value of the question
questiontextThe question as it should be printed

The blueprint, held in the program

FieldTypeDescription
chaptertextWhich chapter to draw from
marksintegerMark value wanted
countintegerHow many questions of that kind the paper needs

Sample contents of questions.csv

chaptermarksquestion
File Handling1Name the mode that opens a file for appending.
File Handling1What does readlines() return?
File Handling1Which function moves the file pointer?
File Handling3Write a function to count the lines starting with 'A' in a text file.
File Handling3Explain the difference between a text file and a binary file.
SQL1Which clause is used to sort the rows of a result?

6How it works, step by step

1
Load

load_bank() reads the CSV and files each question under a (chapter, marks) key.

2
Plan

The blueprint says how many questions of each kind the paper needs.

3
Pick

random.sample() takes that many from the right bucket, never repeating one.

4
Write

Questions are numbered, marks are shown in brackets, and the total is worked out from the paper itself.

7Source code

paper.py
# ---------------------------------------------------------------------------
# paper.py
#
# Builds a question paper from a question bank, following a blueprint of
# chapters and mark values.
#
# The bank is a CSV file a teacher can extend in any spreadsheet. The blueprint
# says how many questions of each kind the paper needs. The program does the
# choosing, and adds the marks up from the paper it actually produced.
# ---------------------------------------------------------------------------

import csv
import random                  # for choosing questions without repeating one

BANK = "questions.csv"


def load_bank():
    """Read the bank and sort the questions into chapter -> marks buckets."""
    bank = {}                  # (chapter, marks) -> list of questions

    with open(BANK, newline="") as f:
        for row in csv.DictReader(f):
            # A tuple is used as the key so that both facts about a question —
            # which chapter and how many marks — identify its bucket together.
            key = (row["chapter"], int(row["marks"]))

            # setdefault() creates the empty list the first time a bucket is
            # met, so the questions can simply be appended.
            bank.setdefault(key, []).append(row["question"])

    return bank


def build_paper(bank, plan, seed=None):
    """plan is a list of (chapter, marks, how_many)."""
    if seed is not None:
        # Fixing the seed makes the same paper come out every time, which is
        # what you want when the same set has to be printed twice.
        random.seed(seed)

    paper = []

    for chapter, marks, count in plan:
        pool = bank.get((chapter, marks), [])   # [] if the bank has none at all

        # Asking for more questions than exist would raise an error, so the
        # program says so and produces a shorter paper instead of stopping.
        if len(pool) < count:
            print("Not enough {}-mark questions in {}".format(marks, chapter))
            count = len(pool)

        # sample() picks without repeating; choice() in a loop could give the
        # same question twice in one paper.
        paper.extend((q, marks) for q in random.sample(pool, count))

    return paper


def write_paper(paper, filename):
    """Write the paper out, numbered, and return its total marks."""
    # The total is added up from the questions actually chosen, so it cannot
    # disagree with the paper.
    total = sum(marks for question, marks in paper)

    with open(filename, "w") as f:
        f.write("LAMBDALAB PUBLIC SCHOOL\n")
        f.write("UNIT TEST — COMPUTER SCIENCE\n")
        f.write("Maximum marks: {}\n\n".format(total))

        # enumerate(..., start=1) numbers the questions from 1 rather than 0.
        for n, (question, marks) in enumerate(paper, start=1):
            f.write("Q{}. {}  [{}]\n".format(n, question, marks))

    return total


# --- the program itself ----------------------------------------------------

# The blueprint: two 1-mark and one 3-mark from File Handling, one 1-mark and
# one 5-mark from SQL.
plan = [("File Handling", 1, 2), ("File Handling", 3, 1), ("SQL", 1, 1), ("SQL", 5, 1)]

paper = build_paper(load_bank(), plan, seed=7)
total = write_paper(paper, "paper.txt")

print(open("paper.txt").read())
print("Total marks:", total)
questions.csv
chapter,marks,question
File Handling,1,Name the mode that opens a file for appending.
File Handling,1,What does readlines() return?
File Handling,1,Which function moves the file pointer?
File Handling,3,Write a function to count the lines starting with 'A' in a text file.
File Handling,3,Explain the difference between a text file and a binary file.
SQL,1,Which clause is used to sort the rows of a result?
SQL,1,Name the SQL command that removes a table completely.
SQL,5,Write SQL to create a table STUDENT and insert two rows into it.
⬇️ Take it with you

The full report as a PDF — cover page, certificate, index, code, output, future scope and references, ready to print and fill in. Or the code on its own as a zip.

or one file:

8Sample output

This is a real run, not a mock-up — the transcript below is what the program actually printed.

Command Prompt
C:\LambdaLab\Projects\Question-Paper> python paper.py
LAMBDALAB PUBLIC SCHOOL
UNIT TEST — COMPUTER SCIENCE
Maximum marks: 11

Q1. What does readlines() return?  [1]
Q2. Name the mode that opens a file for appending.  [1]
Q3. Explain the difference between a text file and a binary file.  [3]
Q4. Which clause is used to sort the rows of a result?  [1]
Q5. Write SQL to create a table STUDENT and insert two rows into it.  [5]

Total marks: 11

Running it also wrote paper.txt. This is what that file held afterwards:

paper.txt
LAMBDALAB PUBLIC SCHOOL
UNIT TEST — COMPUTER SCIENCE
Maximum marks: 11

Q1. What does readlines() return?  [1]
Q2. Name the mode that opens a file for appending.  [1]
Q3. Explain the difference between a text file and a binary file.  [3]
Q4. Which clause is used to sort the rows of a result?  [1]
Q5. Write SQL to create a table STUDENT and insert two rows into it.  [5]

9Testing

Every case below was actually run and the result recorded as it appeared — including the ones expected to fail.

Test caseExpectedActual
Blueprint asking for five questionsFive questions, 11 marksTotal marks: 11
Same blueprint, a different seedDifferent questions, still 11 marksTotal marks: 11
More questions asked for than existA warning, and a shorter paperNot enough 1-mark questions in File Handling
An empty question bankA warning for each blueprint lineNot enough 5-mark questions in SQL

Two kinds of case are in there on purpose. The boundary cases test the edge of a rule, where a program is most often wrong by one. The failure cases check that it refuses cleanly and says why, instead of quietly producing a wrong answer.

10Advantages

Set against the ways the job is done today:

  • A paper follows the blueprint exactly rather than approximately
  • No question can appear twice in the same paper
  • Two sets of the same test can be produced for two halves of a room
  • The total is added from the paper, so it cannot disagree with it
  • The bank grows year on year instead of being rebuilt

11Future scope

What this version does not do

A report should be honest about its own limits, and each of these is the reason for one of the additions below:

  • There is no difficulty rating, so an easy and a hard paper are equally likely
  • Questions used in a previous test can be picked again
  • Diagrams and tables cannot be stored in a CSV question bank
  • The answer key is not produced alongside the paper

Proposed enhancements

This is also where you make the project yours. Pick one or two of these, or something nobody here thought of:

  • Generate several sets at once, labelled Set A, Set B, Set C
  • Produce the answer key alongside the paper
  • Add a difficulty column and balance easy against hard
  • Avoid questions used in the last two tests
  • Export to Word so the school can print it on letterhead

12What you may have to teach yourself

CBSE expects some self-learning in a project, and says so. For this one, that means:

  • random.sample() against random.choice(), and why repeats matter here
  • setdefault(), which is what builds the buckets in one line
  • Optional: python-docx, if the paper must go into a Word template

13Conclusion

A unit test is now built from a blueprint rather than from last year's paper, with the marks totalled from the questions actually chosen.

The bank is the real product. The program is short, and it becomes more useful every time a question is added to the file it reads.

14References

Every report needs a bibliography. This one used:

  • Computer Science with Python, Class XII — the NCERT / CBSE prescribed textbook, for the chapters on file handling and working with text and CSV files
  • Computer Science with Python, Class XI — for functions, lists, dictionaries and string handling
  • Python 3 documentation — https://docs.python.org/3/
  • CBSE Senior School Curriculum, Computer Science (Subject Code 083) — the project guidelines this report follows
  • LambdaLab — https://www.lambdalab.in
Key Takeaway
The PDF above is the whole report. Cover page, certificate, acknowledgement, index, everything on this page, and the references — in the order CBSE marks them, ready to print. The cover page, certificate and acknowledgement arrive with blank rules where names go, because a certificate with somebody else's name printed on it is not a template. Fill those in, get the certificate signed, and replace the problem with one you have looked into yourself.