"""
Python 108 — Quiz Data
10 questions per module, 12 modules = 120 questions total.
Each question: {q, options[4], answer (0-indexed), explanation}
"""

QUIZZES = {
    "Getting started": [
        {"q": "What does print('Hello') do in Python?",
         "options": ["Stores 'Hello' in memory", "Displays 'Hello' on screen", "Creates a variable called Hello", "Imports the Hello module"],
         "answer": 1, "explanation": "print() outputs text to the screen (standard output)."},
        {"q": "Which of these is a valid variable name in Python?",
         "options": ["2name", "my-name", "my_name", "my name"],
         "answer": 2, "explanation": "Variable names can contain letters, digits and underscores, but cannot start with a digit or contain spaces/hyphens."},
        {"q": "What is the data type of: x = 3.14",
         "options": ["int", "str", "float", "bool"],
         "answer": 2, "explanation": "Numbers with a decimal point are float in Python."},
        {"q": "What does len('Python') return?",
         "options": ["5", "6", "7", "Error"],
         "answer": 1, "explanation": "len() counts characters. 'Python' has 6 characters."},
        {"q": "Which string method converts text to uppercase?",
         "options": [".capitalize()", ".title()", ".upper()", ".big()"],
         "answer": 2, "explanation": ".upper() converts all characters to uppercase."},
        {"q": "What is the output of: print(type(True))?",
         "options": ["<class 'int'>", "<class 'bool'>", "<class 'str'>", "<class 'float'>"],
         "answer": 1, "explanation": "True and False are bool (boolean) values in Python."},
        {"q": "Which f-string correctly formats 3.14159 to 2 decimal places?",
         "options": ["f'{3.14159:.2}'", "f'{3.14159:2f}'", "f'{3.14159:.2f}'", "f'{3.14159|2f}'"],
         "answer": 2, "explanation": ":.2f means: format as float with 2 decimal places."},
        {"q": "What does input() return in Python?",
         "options": ["int", "float", "str", "The type the user types"],
         "answer": 2, "explanation": "input() always returns a string — you must cast it if you need int or float."},
        {"q": "What is the result of 17 // 5?",
         "options": ["3.4", "3", "2", "4"],
         "answer": 1, "explanation": "// is floor division — it returns the integer part of the division."},
        {"q": "What does the % operator do?",
         "options": ["Division", "Power", "Remainder (modulo)", "Percentage"],
         "answer": 2, "explanation": "% returns the remainder. 17 % 5 = 2 because 17 = 3×5 + 2."},
    ],

    "Control flow": [
        {"q": "Which keyword checks an alternative condition in Python?",
         "options": ["else if", "elseif", "elif", "otherwise"],
         "answer": 2, "explanation": "Python uses elif (not else if or elseif) for chained conditions."},
        {"q": "What is printed by: x=5; print('yes') if x>3 else print('no')?",
         "options": ["yes", "no", "True", "Error"],
         "answer": 0, "explanation": "x=5 is greater than 3, so the if branch runs and prints 'yes'."},
        {"q": "What does 'break' do inside a loop?",
         "options": ["Skips to the next iteration", "Exits the loop entirely", "Pauses the loop", "Restarts the loop"],
         "answer": 1, "explanation": "break immediately exits the enclosing loop."},
        {"q": "What does 'continue' do inside a loop?",
         "options": ["Exits the loop", "Skips the rest of this iteration and goes to next", "Continues after the loop", "Pauses execution"],
         "answer": 1, "explanation": "continue skips the remaining code in the current iteration and moves to the next one."},
        {"q": "How many times does this loop run: for i in range(3, 10, 2)?",
         "options": ["7", "4", "3", "5"],
         "answer": 1, "explanation": "range(3,10,2) gives 3,5,7,9 — that is 4 values."},
        {"q": "What is the purpose of 'pass' in Python?",
         "options": ["Exit a function", "Skip an iteration", "Do nothing — placeholder", "Pass a value to a function"],
         "answer": 2, "explanation": "pass is a no-op placeholder that keeps empty blocks syntactically valid."},
        {"q": "What is printed: for i in range(5): print(i) — last value?",
         "options": ["5", "4", "3", "6"],
         "answer": 1, "explanation": "range(5) goes from 0 to 4 inclusive. Last value printed is 4."},
        {"q": "Which prints: 1 2 3 5 6 7 (skipping 4)?",
         "options": ["Use break at 4", "Use continue when i==4", "Use pass when i==4", "Use return when i==4"],
         "answer": 1, "explanation": "continue skips the current iteration, so i==4 is skipped and the loop continues."},
        {"q": "What is the output of: x=10; print('A') if x>5 and x<15 else print('B')?",
         "options": ["A", "B", "True", "Error"],
         "answer": 0, "explanation": "10 > 5 is True AND 10 < 15 is True, so 'A' is printed."},
        {"q": "A while loop runs while its condition is:",
         "options": ["False", "True", "None", "Zero"],
         "answer": 1, "explanation": "A while loop continues as long as its condition evaluates to True."},
    ],

    "Functions": [
        {"q": "Which keyword defines a function in Python?",
         "options": ["function", "func", "def", "define"],
         "answer": 2, "explanation": "Python uses the 'def' keyword to define functions."},
        {"q": "What does a function return if no return statement is written?",
         "options": ["0", "''", "None", "Error"],
         "answer": 2, "explanation": "Functions without a return statement implicitly return None."},
        {"q": "What is a default argument?",
         "options": ["An argument with no name", "A fallback value used when no argument is passed", "The first argument always", "A required argument"],
         "answer": 1, "explanation": "Default arguments have a preset value used when the caller doesn't supply one."},
        {"q": "What does *args allow in a function?",
         "options": ["Only keyword arguments", "Any number of positional arguments", "Only two arguments", "Starred imports"],
         "answer": 1, "explanation": "*args collects any number of positional arguments into a tuple."},
        {"q": "What is a lambda function?",
         "options": ["A named function", "An anonymous one-expression function", "A recursive function", "A built-in function"],
         "answer": 1, "explanation": "Lambda functions are anonymous (no name) single-expression functions."},
        {"q": "What is the base case in recursion?",
         "options": ["The condition that calls the function again", "The condition that stops recursion", "The first argument", "The return value"],
         "answer": 1, "explanation": "The base case is the condition that stops recursive calls to prevent infinite recursion."},
        {"q": "What does the LEGB rule describe?",
         "options": ["Loop execution order", "Python's scope lookup order", "List element ordering", "Lambda expression syntax"],
         "answer": 1, "explanation": "LEGB stands for Local, Enclosing, Global, Built-in — Python's variable scope lookup order."},
        {"q": "What is a closure?",
         "options": ["A function that returns None", "An inner function that remembers its enclosing scope", "A function with no arguments", "A built-in function"],
         "answer": 1, "explanation": "A closure is an inner function that captures and remembers variables from its enclosing scope."},
        {"q": "What does map(func, iterable) return?",
         "options": ["A list", "A dict", "An iterator applying func to each element", "None"],
         "answer": 2, "explanation": "map() returns a lazy iterator that applies the function to each element of the iterable."},
        {"q": "What does **kwargs allow?",
         "options": ["Any number of positional args", "Any number of keyword arguments", "Double multiplication", "Import all names"],
         "answer": 1, "explanation": "**kwargs collects any number of keyword arguments into a dictionary."},
    ],

    "Data structures": [
        {"q": "Which data structure is ordered and mutable?",
         "options": ["tuple", "set", "list", "frozenset"],
         "answer": 2, "explanation": "Lists are ordered (maintain insertion order) and mutable (can be changed after creation)."},
        {"q": "What does list.append(x) do?",
         "options": ["Inserts x at position 0", "Adds x to the end of the list", "Removes x from the list", "Returns the index of x"],
         "answer": 1, "explanation": "append() adds an element to the end of a list."},
        {"q": "Which is a valid list comprehension?",
         "options": ["[x*2 for x in range(5)]", "{x*2 for x in range(5)}", "(x*2 for x in range(5))", "list(x*2, range(5))"],
         "answer": 0, "explanation": "List comprehensions use square brackets: [expression for item in iterable]."},
        {"q": "What makes a tuple different from a list?",
         "options": ["Tuples are ordered, lists are not", "Tuples are immutable, lists are mutable", "Tuples allow duplicates, lists do not", "Tuples are faster to create"],
         "answer": 1, "explanation": "Tuples cannot be changed after creation — they are immutable."},
        {"q": "What does a set guarantee?",
         "options": ["Ordered elements", "Unique elements", "Sorted elements", "Key-value pairs"],
         "answer": 1, "explanation": "Sets contain only unique elements — duplicates are automatically removed."},
        {"q": "How do you safely get a dict value that might not exist?",
         "options": ["dict[key]", "dict.get(key)", "dict.get(key, default)", "dict.fetch(key)"],
         "answer": 2, "explanation": "dict.get(key, default) returns the default value if the key doesn't exist, instead of raising KeyError."},
        {"q": "What is the output of: {x: x**2 for x in range(3)}?",
         "options": ["{0,1,4}", "{0:0, 1:1, 2:4}", "[0,1,4]", "{0:0, 1:2, 2:4}"],
         "answer": 1, "explanation": "This is a dict comprehension — it creates {0:0, 1:1, 2:4}."},
        {"q": "Which operation finds elements in set A but NOT in set B?",
         "options": ["A | B", "A & B", "A - B", "A ^ B"],
         "answer": 2, "explanation": "A - B (difference) returns elements in A that are not in B."},
        {"q": "How do you access a nested dict value: data={'a':{'b':42}}?",
         "options": ["data['a','b']", "data['a']['b']", "data.a.b", "data.get('a','b')"],
         "answer": 1, "explanation": "Use chained indexing: data['a']['b'] first gets the inner dict, then accesses 'b'."},
        {"q": "What does list.pop() do by default?",
         "options": ["Removes the first element", "Removes and returns the last element", "Returns the last element without removing", "Clears the list"],
         "answer": 1, "explanation": "pop() with no argument removes and returns the last element of the list."},
    ],

    "Files & exceptions": [
        {"q": "Which mode opens a file for writing (creates if not exists, overwrites if exists)?",
         "options": ["'r'", "'a'", "'w'", "'x'"],
         "answer": 2, "explanation": "'w' opens for writing, creating the file if it doesn't exist and truncating it if it does."},
        {"q": "What is the main advantage of using 'with open()' over open()?",
         "options": ["It's faster", "It automatically closes the file when the block ends", "It supports more file types", "It allows reading and writing simultaneously"],
         "answer": 1, "explanation": "The 'with' statement is a context manager that automatically closes the file even if an error occurs."},
        {"q": "Which exception is raised when you try to open a file that doesn't exist?",
         "options": ["ValueError", "TypeError", "FileNotFoundError", "IOError"],
         "answer": 2, "explanation": "FileNotFoundError is raised when the file or directory doesn't exist."},
        {"q": "What does json.dumps() do?",
         "options": ["Reads JSON from a file", "Converts a Python object to a JSON string", "Validates JSON format", "Deletes JSON data"],
         "answer": 1, "explanation": "json.dumps() serializes a Python object (dict, list, etc.) into a JSON-formatted string."},
        {"q": "Which block in try/except ALWAYS runs regardless of errors?",
         "options": ["try", "except", "else", "finally"],
         "answer": 3, "explanation": "The 'finally' block always runs — whether an exception occurred or not. Used for cleanup."},
        {"q": "What does the 'else' block in try/except do?",
         "options": ["Runs when an exception occurs", "Runs when NO exception occurs", "Always runs", "Runs after finally"],
         "answer": 1, "explanation": "The 'else' block runs only if the try block completed without raising any exception."},
        {"q": "How do you raise a custom exception?",
         "options": ["throw MyError()", "raise MyError()", "except MyError()", "return MyError()"],
         "answer": 1, "explanation": "The 'raise' keyword is used to throw an exception in Python."},
        {"q": "What is csv.DictReader used for?",
         "options": ["Writing CSV with headers", "Reading CSV rows as dictionaries", "Sorting CSV data", "Validating CSV format"],
         "answer": 1, "explanation": "csv.DictReader reads a CSV file and returns each row as an OrderedDict using the header row as keys."},
        {"q": "Which exception catches all exceptions?",
         "options": ["except Error", "except All", "except Exception", "except *"],
         "answer": 2, "explanation": "Exception is the base class for most built-in exceptions. Catching it handles almost all errors."},
        {"q": "What does 'a' mode do when opening a file?",
         "options": ["Overwrites the file", "Reads from end of file", "Appends to end without deleting existing content", "Creates a new empty file only"],
         "answer": 2, "explanation": "'a' (append) mode adds content to the end of the file without erasing what's already there."},
    ],

    "OOP basics": [
        {"q": "What is __init__ in a Python class?",
         "options": ["A destructor", "A constructor called when an object is created", "A class variable", "A static method"],
         "answer": 1, "explanation": "__init__ is the constructor — it's automatically called when you create a new instance of the class."},
        {"q": "What does 'self' refer to in a class method?",
         "options": ["The class itself", "The current instance of the class", "The parent class", "The module"],
         "answer": 1, "explanation": "'self' refers to the specific instance (object) on which the method is being called."},
        {"q": "What is inheritance in OOP?",
         "options": ["A class copying its own methods", "A child class acquiring attributes and methods from a parent class", "A method calling itself", "Hiding internal data"],
         "answer": 1, "explanation": "Inheritance allows a child class to reuse (inherit) the attributes and methods of a parent class."},
        {"q": "What does super() do?",
         "options": ["Creates a superclass", "Calls a method from the parent class", "Makes a class abstract", "Returns the class name"],
         "answer": 1, "explanation": "super() gives access to methods from the parent (super) class, often used to call the parent's __init__."},
        {"q": "What is encapsulation?",
         "options": ["Running code in parallel", "Hiding internal details and exposing only necessary parts", "Inheriting from multiple classes", "Overriding methods"],
         "answer": 1, "explanation": "Encapsulation bundles data and methods, hiding internal implementation details from outside."},
        {"q": "What does __str__ define for a class?",
         "options": ["How the object is stored", "The string representation shown by print(obj)", "The object's type", "How objects are compared"],
         "answer": 1, "explanation": "__str__ defines the human-readable string representation returned when you print() or str() an object."},
        {"q": "What is polymorphism?",
         "options": ["A class with many parents", "Different classes responding to the same method call in their own way", "A method with many arguments", "A loop that changes type"],
         "answer": 1, "explanation": "Polymorphism means different object types can be used through the same interface — each responds in its own way."},
        {"q": "What decorator creates a class with auto-generated __init__ and __repr__?",
         "options": ["@staticmethod", "@classmethod", "@property", "@dataclass"],
         "answer": 3, "explanation": "@dataclass automatically generates __init__, __repr__, and __eq__ based on class field annotations."},
        {"q": "What is a @staticmethod?",
         "options": ["A method that takes cls as first argument", "A method that takes self as first argument", "A method with no self or cls — belongs to the class but doesn't access instance", "A method that can't be overridden"],
         "answer": 2, "explanation": "Static methods don't receive self or cls — they're regular functions that logically belong to the class."},
        {"q": "How do you denote a private attribute by convention in Python?",
         "options": ["private attr", "#attr", "_attr or __attr", "@private"],
         "answer": 2, "explanation": "Single underscore _attr signals 'internal use'. Double underscore __attr triggers name mangling for stronger privacy."},
    ],

    "Modules & packages": [
        {"q": "Which statement imports only the sqrt function from math?",
         "options": ["import math.sqrt", "from math import sqrt", "include math sqrt", "using math::sqrt"],
         "answer": 1, "explanation": "'from module import name' imports a specific name from a module."},
        {"q": "What does 'import math as m' allow you to do?",
         "options": ["Import multiple modules", "Use m as an alias for math", "Make math faster", "Import math privately"],
         "answer": 1, "explanation": "'as' creates an alias — you can then use m.sqrt() instead of math.sqrt()."},
        {"q": "What is __name__ == '__main__' used for?",
         "options": ["Check if the module has a main function", "Run code only when the file is executed directly, not when imported", "Name the module", "Check Python version"],
         "answer": 1, "explanation": "When a file is run directly, __name__ is '__main__'. When imported, it's the module name. This guards code from running on import."},
        {"q": "What does os.path.join() do?",
         "options": ["Connects to a network path", "Joins path components correctly for the OS", "Lists directory contents", "Creates a new directory"],
         "answer": 1, "explanation": "os.path.join() builds file paths correctly using the right separator for the operating system."},
        {"q": "What is the purpose of __init__.py in a package?",
         "options": ["Initialise all Python files", "Mark a directory as a Python package", "Run when Python starts", "Import all submodules automatically"],
         "answer": 1, "explanation": "__init__.py tells Python that the directory is a package, enabling imports from it."},
        {"q": "Which module provides the choice() function for random selection?",
         "options": ["os", "sys", "random", "math"],
         "answer": 2, "explanation": "random.choice() picks a random element from a sequence."},
        {"q": "What does pip install do?",
         "options": ["Runs a Python file", "Installs a third-party package from PyPI", "Creates a virtual environment", "Updates Python"],
         "answer": 1, "explanation": "pip is Python's package installer — pip install downloads and installs packages from PyPI."},
        {"q": "What is a virtual environment used for?",
         "options": ["Running Python faster", "Isolating project dependencies from each other", "Testing Python online", "Creating GUIs"],
         "answer": 1, "explanation": "Virtual environments create isolated spaces where each project can have its own package versions."},
        {"q": "What does datetime.today().strftime('%d %b %Y') return?",
         "options": ["A timestamp in seconds", "A formatted date string like '02 May 2026'", "A datetime object", "An integer date"],
         "answer": 1, "explanation": "strftime formats a datetime object as a string. %d=day, %b=short month name, %Y=4-digit year."},
        {"q": "Which module would you use to find the square root of a number?",
         "options": ["os", "sys", "math", "random"],
         "answer": 2, "explanation": "math.sqrt() computes the square root. The math module provides mathematical functions."},
    ],

    "Iterators & generators": [
        {"q": "What method must an iterator implement to return the next value?",
         "options": ["__iter__", "__next__", "__yield__", "__get__"],
         "answer": 1, "explanation": "__next__() returns the next value in the sequence. When done, it raises StopIteration."},
        {"q": "What keyword turns a function into a generator?",
         "options": ["return", "yield", "next", "iterate"],
         "answer": 1, "explanation": "The 'yield' keyword makes a function a generator — it pauses and resumes, producing values lazily."},
        {"q": "What is the main benefit of a generator over a list?",
         "options": ["Generators are always faster", "Generators use less memory by producing values one at a time", "Generators can hold more items", "Generators are easier to write"],
         "answer": 1, "explanation": "Generators produce values lazily (one at a time) instead of storing everything in memory at once."},
        {"q": "What does enumerate(['a','b','c']) produce?",
         "options": ["[1,2,3]", "[(0,'a'),(1,'b'),(2,'c')]", "{'a':0,'b':1,'c':2}", "('a','b','c')"],
         "answer": 1, "explanation": "enumerate() adds a counter to each item, yielding (index, value) tuples starting at 0."},
        {"q": "What does zip([1,2,3], ['a','b','c']) produce?",
         "options": ["[1,'a',2,'b',3,'c']", "[(1,'a'),(2,'b'),(3,'c')]", "{1:'a',2:'b',3:'c'}", "[[1,'a'],[2,'b'],[3,'c']]"],
         "answer": 1, "explanation": "zip() pairs up elements from multiple iterables, returning an iterator of tuples."},
        {"q": "What does itertools.chain([1,2],[3,4]) produce?",
         "options": ["[[1,2],[3,4]]", "[1,2,3,4]", "(1,2,3,4)", "{1,2,3,4}"],
         "answer": 1, "explanation": "chain() concatenates multiple iterables into a single sequence: 1,2,3,4."},
        {"q": "What is a generator expression?",
         "options": ["A list comprehension with yield", "A lazy comprehension using () instead of []", "A set comprehension", "A dict comprehension"],
         "answer": 1, "explanation": "Generator expressions use () and are lazy — they don't compute all values upfront like list comprehensions."},
        {"q": "What does sorted([3,1,4,1,5], key=lambda x:-x) return?",
         "options": ["[1,1,3,4,5]", "[5,4,3,1,1]", "[-5,-4,-3,-1,-1]", "[5,4,3,1]"],
         "answer": 1, "explanation": "key=lambda x:-x sorts by negative value, giving descending order: [5,4,3,1,1]."},
        {"q": "What does first, *rest = [1,2,3,4,5] give us?",
         "options": ["first=1, rest=2", "first=1, rest=[2,3,4,5]", "first=[1], rest=[2,3,4,5]", "Error"],
         "answer": 1, "explanation": "Starred assignment captures the 'rest' — first=1 and rest=[2,3,4,5]."},
        {"q": "What is the walrus operator :=?",
         "options": ["A comparison operator", "An assignment expression that assigns and returns a value in one step", "A string format operator", "A list slicing operator"],
         "answer": 1, "explanation": ":= assigns a value AND returns it, allowing assignment inside expressions like while or comprehensions."},
    ],

    "Decorators & advanced functions": [
        {"q": "What does a decorator do to a function?",
         "options": ["Renames it", "Wraps it to add behaviour without changing its source code", "Deletes it after use", "Makes it run faster"],
         "answer": 1, "explanation": "A decorator wraps a function, adding behaviour before and/or after the original function runs."},
        {"q": "What does @functools.wraps do?",
         "options": ["Makes a function faster", "Preserves the wrapped function's __name__ and __doc__", "Wraps a class", "Caches function results"],
         "answer": 1, "explanation": "@functools.wraps copies the original function's metadata (name, docstring) to the wrapper."},
        {"q": "What does the @property decorator do?",
         "options": ["Makes an attribute public", "Allows a method to be accessed like an attribute", "Prevents attribute deletion", "Marks a class variable"],
         "answer": 1, "explanation": "@property lets you define a method that is accessed like an attribute — no parentheses needed."},
        {"q": "What does @lru_cache do?",
         "options": ["Clears the cache", "Caches function results so repeated calls with same args are instant", "Limits function calls", "Logs function calls"],
         "answer": 1, "explanation": "@lru_cache stores results of previous calls. If the function is called again with the same arguments, the cached result is returned instantly."},
        {"q": "What is functools.partial used for?",
         "options": ["Partial class inheritance", "Pre-filling some arguments of a function to create a specialised version", "Running a function partially", "Importing part of a module"],
         "answer": 1, "explanation": "partial() creates a new function with some arguments pre-filled, reducing repetition."},
        {"q": "What is a decorator factory?",
         "options": ["A function that creates classes", "A function that returns a decorator (so the decorator can accept arguments)", "A built-in Python tool", "A class that decorates functions"],
         "answer": 1, "explanation": "A decorator factory is a function that takes arguments and returns a decorator — adding one extra level of nesting."},
        {"q": "What does a @classmethod receive as its first argument?",
         "options": ["self — the instance", "cls — the class itself", "Nothing", "The module"],
         "answer": 1, "explanation": "@classmethod receives cls (the class) as its first argument, not self (the instance)."},
        {"q": "What are type hints used for?",
         "options": ["Making code run faster", "Documenting expected types — caught by type checkers like mypy", "Enforcing types at runtime", "Importing types"],
         "answer": 1, "explanation": "Type hints document expected types. Python doesn't enforce them at runtime, but tools like mypy can catch type errors."},
        {"q": "What does __enter__ and __exit__ enable?",
         "options": ["Recursive functions", "Custom context managers (for use with 'with' statement)", "Class inheritance", "Module imports"],
         "answer": 1, "explanation": "Implementing __enter__ and __exit__ makes an object a context manager — usable with the 'with' statement."},
        {"q": "What is memoisation?",
         "options": ["Writing comments in code", "Caching function results to avoid recomputing the same inputs", "Storing variables in memory", "A type of recursion"],
         "answer": 1, "explanation": "Memoisation stores results of function calls. When the function is called with the same arguments again, it returns the cached result instead of recomputing."},
    ],

    "Working with data": [
        {"q": "Which module provides regular expression support in Python?",
         "options": ["regex", "re", "pattern", "match"],
         "answer": 1, "explanation": "The 're' module provides regular expression operations in Python."},
        {"q": "What does re.findall(pattern, string) return?",
         "options": ["The first match only", "A list of all non-overlapping matches", "True/False", "A match object"],
         "answer": 1, "explanation": "findall() returns a list of all matches found in the string."},
        {"q": "What does collections.Counter do?",
         "options": ["Counts list length", "Counts occurrences of each element in an iterable", "Creates a countdown timer", "Counts function calls"],
         "answer": 1, "explanation": "Counter creates a dictionary-like object counting how many times each element appears."},
        {"q": "Why use decimal.Decimal instead of float for money?",
         "options": ["Decimal is faster", "Decimal avoids floating-point precision errors (e.g. 0.1+0.2 != 0.3)", "Decimal uses less memory", "Decimal supports more operations"],
         "answer": 1, "explanation": "Floats have precision issues (0.1+0.2=0.30000000000004). Decimal provides exact decimal arithmetic."},
        {"q": "Which SQLite method executes a query with multiple rows of data?",
         "options": ["execute()", "executemany()", "executescript()", "executeall()"],
         "answer": 1, "explanation": "executemany() efficiently inserts/updates multiple rows at once using a sequence of parameter tuples."},
        {"q": "What does re.sub(pattern, replacement, string) do?",
         "options": ["Finds all matches", "Replaces all matches with the replacement string", "Splits string by pattern", "Returns match count"],
         "answer": 1, "explanation": "re.sub() finds all occurrences of the pattern and replaces them with the replacement string."},
        {"q": "What does collections.defaultdict do?",
         "options": ["Sorts a dict by default", "Provides a default value for missing keys automatically", "Limits dict size", "Orders dict by insertion"],
         "answer": 1, "explanation": "defaultdict automatically creates a default value for missing keys, avoiding KeyError."},
        {"q": "In SQLite, what does ':memory:' as the database path do?",
         "options": ["Saves to RAM permanently", "Creates an in-memory database that exists only while the program runs", "Loads from memory cache", "Creates a backup"],
         "answer": 1, "explanation": "':memory:' creates a temporary database in RAM — perfect for testing as it disappears when the connection closes."},
        {"q": "What does numpy array vectorisation mean?",
         "options": ["Converting arrays to vectors", "Applying operations to entire arrays at once without Python loops", "Sorting array elements", "Creating multi-dimensional arrays"],
         "answer": 1, "explanation": "Vectorisation applies operations to whole arrays at once using optimised C code — much faster than Python loops."},
        {"q": "What does json.loads() do?",
         "options": ["Loads a JSON file from disk", "Parses a JSON string into a Python object", "Saves Python objects as JSON", "Validates JSON syntax"],
         "answer": 1, "explanation": "json.loads() (load string) parses a JSON-formatted string into a Python dict/list/etc."},
    ],

    "Concurrency & testing": [
        {"q": "What is the difference between threading and multiprocessing in Python?",
         "options": ["No difference", "Threads share memory; processes have separate memory and bypass the GIL", "Processes are slower always", "Threads use multiple CPUs; processes use one"],
         "answer": 1, "explanation": "Threads share memory (limited by GIL for CPU tasks). Processes have separate memory and can truly run in parallel on multiple CPUs."},
        {"q": "What does 'async def' define?",
         "options": ["A faster function", "A coroutine function that can be paused and resumed", "A thread", "A background process"],
         "answer": 1, "explanation": "async def defines a coroutine — a function that can be paused at 'await' points and resumed later."},
        {"q": "What does 'await' do in async Python?",
         "options": ["Pauses the whole program", "Pauses the current coroutine until the awaited task completes, letting others run", "Creates a new thread", "Returns a value immediately"],
         "answer": 1, "explanation": "'await' suspends the current coroutine, allowing the event loop to run other tasks until the result is ready."},
        {"q": "What is the purpose of unittest.TestCase?",
         "options": ["A class that speeds up code", "A base class providing test methods like assertEqual and assertRaises", "A function that runs tests", "A module for timing tests"],
         "answer": 1, "explanation": "TestCase is the base class for unit tests — it provides assertion methods to verify expected behaviour."},
        {"q": "What does mock.patch do in unit testing?",
         "options": ["Fixes bugs automatically", "Temporarily replaces a real object with a controllable fake during tests", "Patches the Python version", "Speeds up test execution"],
         "answer": 1, "explanation": "patch() replaces a real function/class with a Mock object during the test, letting you control its behaviour without real side effects."},
        {"q": "What logging level is ABOVE WARNING?",
         "options": ["DEBUG", "INFO", "ERROR", "NOTICE"],
         "answer": 2, "explanation": "Python logging levels in order: DEBUG < INFO < WARNING < ERROR < CRITICAL."},
        {"q": "What does asyncio.gather() do?",
         "options": ["Collects results into a list synchronously", "Runs multiple coroutines concurrently and waits for all to finish", "Creates a new event loop", "Cancels running tasks"],
         "answer": 1, "explanation": "gather() schedules multiple coroutines to run concurrently and returns their results when all are done."},
        {"q": "What is cProfile used for?",
         "options": ["Code formatting", "Measuring where a program spends its time (profiling)", "Creating C extensions", "Checking code coverage"],
         "answer": 1, "explanation": "cProfile is Python's built-in profiler — it shows which functions are called, how often, and how long they take."},
        {"q": "What does @pytest.mark.parametrize do?",
         "options": ["Marks a test to skip", "Runs a test multiple times with different input values", "Makes a test run in parallel", "Measures test performance"],
         "answer": 1, "explanation": "parametrize runs the same test function with multiple sets of arguments, avoiding duplicate test code."},
        {"q": "What is a race condition in multithreading?",
         "options": ["A competition between threads to finish first", "A bug where output depends on unpredictable thread execution order", "A fast threading technique", "A type of deadlock"],
         "answer": 1, "explanation": "A race condition occurs when two threads access shared data simultaneously and the result depends on their unpredictable execution order."},
    ],

    "Capstone projects": [
        {"q": "Which module parses command-line arguments in Python?",
         "options": ["sys", "os", "argparse", "cli"],
         "answer": 2, "explanation": "argparse is the standard library module for building command-line interfaces with flags and arguments."},
        {"q": "What is the best way to persist data between program runs in a simple app?",
         "options": ["Global variables", "Save to a JSON or SQLite file", "Use print statements", "Hardcode the data"],
         "answer": 1, "explanation": "JSON files or SQLite databases persist data between runs — global variables are lost when the program exits."},
        {"q": "In OOP design, what is the Single Responsibility Principle?",
         "options": ["A class should have only one method", "A class should have only one reason to change (one responsibility)", "A function should only call itself", "A module should contain only one class"],
         "answer": 1, "explanation": "SRP states that a class should do one thing well — making it easier to maintain and test."},
        {"q": "What does BeautifulSoup help with?",
         "options": ["Making HTTP requests", "Parsing and extracting data from HTML/XML documents", "Generating HTML pages", "Testing web applications"],
         "answer": 1, "explanation": "BeautifulSoup parses HTML/XML and provides easy ways to search and extract data from web pages."},
        {"q": "What is the purpose of a requirements.txt file?",
         "options": ["List the features of the project", "List all package dependencies so others can recreate the environment", "Store user requirements", "Configure the database"],
         "answer": 1, "explanation": "requirements.txt lists all packages and versions needed, allowing others to install them with 'pip install -r requirements.txt'."},
        {"q": "Which approach is best for a bank system's account balance?",
         "options": ["A public variable anyone can change", "A private attribute with deposit/withdraw methods that validate input", "A global variable", "A class variable shared by all accounts"],
         "answer": 1, "explanation": "Encapsulating balance as private with controlled methods prevents invalid states (e.g. negative deposits)."},
        {"q": "What makes a good capstone project?",
         "options": ["Uses as many modules as possible", "Solves a real problem by combining multiple Python concepts cleanly", "Is as long as possible", "Uses only the latest Python features"],
         "answer": 1, "explanation": "Good projects solve real problems using appropriate tools — demonstrating understanding through practical application."},
        {"q": "What is the difference between a script and a module?",
         "options": ["No difference", "A script is run directly; a module is imported and reused by other code", "A module is faster", "A script has no functions"],
         "answer": 1, "explanation": "Scripts are meant to be run directly. Modules are designed to be imported and provide reusable functions/classes."},
        {"q": "What is an API in the context of web requests?",
         "options": ["A Python package manager", "An interface that lets programs communicate — usually via HTTP returning JSON", "A type of database", "A Python decorator"],
         "answer": 1, "explanation": "An API (Application Programming Interface) defines how programs talk to each other — web APIs typically use HTTP and return JSON data."},
        {"q": "What does 'separation of concerns' mean in software design?",
         "options": ["Having no global variables", "Dividing a program into distinct sections each handling one aspect (data, logic, UI)", "Using multiple files", "Separating tests from code"],
         "answer": 1, "explanation": "Separation of concerns means each part of the code handles one aspect — making it easier to change, test and understand."},
    ],
}

# Slug map for URLs (module name → URL slug)
MODULE_SLUGS = {
    "Getting started":               "getting-started",
    "Control flow":                  "control-flow",
    "Functions":                     "functions",
    "Data structures":               "data-structures",
    "Files & exceptions":            "files-exceptions",
    "OOP basics":                    "oop-basics",
    "Modules & packages":            "modules-packages",
    "Iterators & generators":        "iterators-generators",
    "Decorators & advanced functions": "decorators",
    "Working with data":             "working-with-data",
    "Concurrency & testing":         "concurrency-testing",
    "Capstone projects":             "capstone-projects",
}

SLUG_TO_MODULE = {v: k for k, v in MODULE_SLUGS.items()}

def get_quiz(module_name):
    return QUIZZES.get(module_name, [])

def get_module_from_slug(slug):
    return SLUG_TO_MODULE.get(slug)

def get_slug_from_module(module_name):
    return MODULE_SLUGS.get(module_name)
