Skip to main content

QLCpy

Generates questions about concrete constructs and patterns in a given Python program. These questions (including answering options) can be posed to a learner to practice introductory programming. These questions include elements to develop program comprehension and program tracing.

Automatic generation enables systems to pose the generated questions to leaners about their own programs that they previously programmed. Such Questions About Learners' Code (QLCs) may have self-reflection and self-explanation effects that are of interest in computing education research.

References

The concept of Questions About Learners' Code (QLCs) is first introduced by Lehtinen et al. in Let's Ask Students About Their Programs, Automatically.


Example result

For the file test/sample_code.py:

    from typing import List

    def find_first(words_list: List[str], initial: str) -> int:
      f = False
      for i in range(len(words_list)):
        if words_list[i].startswith(initial):
        return i

    def count_average() -> None:
      s = 0
      n = 0
      word = None
      while word is None or word != '':
        word = input('Enter number or empty line to count average')
        try:
          s += int(word)
          n += 1
        except ValueError:
          print('Not a number')
      if n > 0:
        print('Average', s / n)
      print('No numbers')

We use the CLI to create one question of each available type:

     % qlcpy test/sample_code.py --call 'find_first(["lorem", "ipsum", "dolor", "sit", "amet"], "s")' -n 9 --unique
    Which of the following are variable names in the program? [VariableNames]
      if: A reserved word in programming language [reserved_word]
      input: A function that is built in to programming language [builtin_function]
    * n: A variable in the program [variable]
      other: This word was not used in the program [unused_word]
    * word: A variable in the program [variable]

    Which of the following are parameter names of the function declared on line 3? [ParameterNames]
      f: A variable in the program [variable]
      find_first: A name of the function [function]
      i: A variable in the program [variable]
    * initial: A parameter of the function [parameter]
    * words_list: A parameter of the function [parameter]

    A program loop starts on line 5. Which is the last line inside it? [LoopEnd]
      4: The loop starts after this line [line_before_block]
      6: This line is inside the loop BUT it is not the last one [line_inside_block]
    * 7: Correct, this is the last line inside the loop [last_line_inside_block]
      8: The loop ends before this line [line_after_block]

    A value is accessed from variable <em>i</em> on line 6. On which line is <em>i</em> created? [VariableDeclaration]
      4: This is a random line that does not handle the given variable [random_line]
    * 5: Correct, this is the line where the variable is created. [declaration_line]
      6: This line references (reads or assigns) the given variable BUT it is created before [reference_line]
      7: This line references (reads or assigns) the given variable BUT it is created before [reference_line]

    From which line program execution may continue to line 18? [ExceptSource]
      13: Except-block cannot be entered from outside the corresponding try-block. [before_try_block]
      15: At least the first line inside try-block starts executing. [try_line]
    * 16: Correct, this line can raise an error of the expected type. [source_line]
      17: This line does NOT raise an error of the expected type. [not_source_line]

    Which of the following best describes the purpose of line 13? [LinePurpose]
      Accepts new data: Incorrect. [read_input]
      Guards against division by zero: Incorrect. [zero_div_guard]
      Ignores unwanted input: Incorrect. [ignores_input]
    * Is a condition for ending program: Correct. [end_condition]

    Which of the following best describes the role of variable <em>s</em>that is created on line 10? [VariableRole]
      A <em>fixed value</em> that is not changed after created: Incorrect. [fixed]
    * A <em>gatherer</em> that combines new values to itself: Correct. [gatherer]
      A <em>stepper</em> that systematically goes through evenly spaced values: Incorrect. [stepper]
      The variable is never accessed and could be removed: Incorrect. [dead]

    Line 5 has a loop structure. How many times does the loop execute when running <em>find_first(["lorem", "ipsum", "dolor", "sit", "amet"], "s")</em>? [LoopCount]
    * 4: Correct, this is the number of times the loop executed. [correct_count]
      5: This number is off by one. [one_off_count]
      6: This is an incorrect, random number. [random_count]
      7: This is an incorrect, random number. [random_count]

    Line 5 declares a variable named <em>i</em>. Which values and in which order are assigned to the variable when running <em>find_first(["lorem", "ipsum", "dolor", "sit", "amet"], "s")</em>? [VariableTrace]
      0, 1, 2: This sequence is missing a value that was assigned to the variable. [miss_value]
    * 0, 1, 2, 3: Correct, these values were assigned in this order to the variable. [correct_trace]
      3, 1, 0, 2: This is an incorrect, random sequence of values. [random_values]
      3, 1, 2: This is an incorrect, random sequence of values. [random_values]

Installation

pip install qlcpy

Usage

The package offers a CLI for test prints as well as JSON output. See the example section above for example output. Below is the usage instruction from the command.

     % qlcpy --help
    usage: __main__.py [-h] [-m] [-c CALL] [-sc SILENT_CALL] [-i INPUT] [-n N]
                       [-t TYPES [TYPES ...]] [-u] [-l LANG] [--json]
                       [--list-types]
                       [program]

    QLCpy generates questions that target analysed facts about the given program

    positional arguments:
      program               A python program file

    optional arguments:
      -h, --help            show this help message and exit
      -m, --main            Run with "__name__" = "__main__"
      -c CALL, --call CALL  A python call to execute
      -sc SILENT_CALL, --silent-call SILENT_CALL
                            A python call to execute silently without including it
                            in the question prompts
      -i INPUT, --input INPUT
                            A text file to use as stdin
      -n N                  Number of questions (at maximum)
      -t TYPES [TYPES ...], --types TYPES [TYPES ...]
                            Only these question types
      -u, --unique          Only unique question types
      -l LANG, --lang LANG  Language code for the text (en, fi)
      --json                Print question data as JSON
      --list-types          List available question types

For programmatic integration the library offers a generate function that offers the same generation options as the CLI command. Type hints are included and models.py describes the input and output data. Below is an example python program using the library.

    import qlcpy
    
    with open('test/sample_code.py', 'r') as f:
      src = f.read()
    
    qlcs = qlcpy.generate(
        src,
        [
            qlcpy.QLCRequest(1, types=['LoopCount', 'VariableTrace']),
            qlcpy.QLCRequest(10, fill=True, unique_types=True),
        ],
        call='find_first(["lorem", "ipsum", "dolor", "sit", "amet"], "s")',
    )

    for qlc in qlcs:
        print(f'{qlc.question} = {", ".join(str(o.answer) for o in qlc.options if o.correct)}')
    
    import json
    print(json.dumps(list(qlc.to_dict() for qlc in qlcs)))

Metadata

Release files for qlcpy 1.0.18

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for qlcpy 1.0.18
File Size Uploaded
qlcpy-1.0.18.tar.gz 27.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for qlcpy 1.0.18
File Interpreter ABI Platform
qlcpy-1.0.18-py3-none-any.whl Python 3 none any Details

Total release size: 59.0 kB

Release files / qlcpy-1.0.18.tar.gz

Download URL qlcpy-1.0.18.tar.gz
Size 27.3 kB
Tags Source
SHA-256 checksum
How to use checksums
3dfeddac2465d1223e5529e0401b12e591d487aefce06c355e3dcd5cd8831937
BLAKE2b-256 checksum
How to use checksums
69ad162ef22550badcac09b445bdf5f6c33bcc619fe7170ef049e210635290eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.10.12

Release files / qlcpy-1.0.18-py3-none-any.whl

Download URL qlcpy-1.0.18-py3-none-any.whl
Size 31.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b790fc0382212a8fb250ede2fa8b6bcf17eabe9f9b3f43c19fa6a60c697efaf3
BLAKE2b-256 checksum
How to use checksums
d35dd9cf33f86d993d9b2cdff5cd7ca16f3d35979b13de452ff321872f64d2b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.10.12

Release history Release notifications | RSS feed

This release

1.0.18 This release

2 release files

1.0.16

2 release files

1.0.15

2 release files

1.0.13

2 release files

1.0.11

2 release files

1.0.10

2 release files

1.0.9

2 release files

1.0.4

2 release files

1.0.3

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page