Skip to main content
CIT 5920 — Fall 2025
Sli.do Ed Discussion PrairieLearn Panopto Gradescope Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

PrairieLearn Guide for TAs

Getting Started

  1. Provide your GitHub username to be added as a collaborator to the course repository on GitHub.
  2. Provide your email address to be given access to view the course questions on the PrairieLearn website.

Setting up your Development Environment

This information is also provided in the local installation guide for PrairieLearn, but included here for completeness:

  1. Install Docker Desktop on your computer by following the instructions for your operating system: https://www.docker.com/products/docker-desktop/
  2. If you are using Windows, also set up WSL 2 (Windows Subsystem for Linux) by following these steps:

Running PrairieLearn Locally

  1. Clone the course repository to your local machine. Make a note of the directory path.
    git clone https://github.com/PrairieLearn/pl-upenn-cit5920/
    
  2. Open a terminal (if using Windows, open the WSL terminal) and run the following command to start PrairieLearn with the sample course:
    docker run -it --rm -p 3000:3000 prairielearn/prairielearn
    
    To use your own course, mount the directory using the -v flag:
    docker run -it --rm -p 3000:3000 -v /path/to/your/course:/course prairielearn/prairielearn
    
    Replace /path/to/your/course with the path to your cloned course repository.
  3. Open a web browser and navigate to http://localhost:3000/pl to view PrairieLearn running locally.
  4. If you encounter issues, consult the PrairieLearn documentation on installing locally (https://prairielearn.readthedocs.io/en/latest/installing/) or ask for help in the PrairieLearn Slack community (https://www.prairielearn.com/slack).
  5. Once you have PrairieLearn running successfully, post a message in the #prairie-learn Slack channel to let us know.

Exploring Existing Questions

  1. Go to the course’s PrairieLearn page and browse through the existing questions. For example, here’s the “Union of Two Sets” question listed in the question bank:

    Screenshot of the “Union of Two Sets” question on PrairieLearn question bank of the course

    and here is the question itself:

    Screenshot of a “Union of Two Sets” question instance

  2. Find the corresponding source code for this question in the GitHub repository. In this case, the relevant files are:

    • info.json:

      {
        "uuid": "506e2a79-27e7-4fa5-ac58-2916a8330147",
        "title": "Union of Two Sets",
        "topic": "Set Theory",
        "tags": [
          "sets",
          "union",
          "autograded",
          "randomized",
          "practice",
          "short"
        ],
        "type": "v3"
      }
      
    • question.html:

      <pl-question-panel>
        <p>Consider two sets:</p>
        <p>\( A = \{ {{params.a}} \} \)</p>
        <p>\( B = \{ {{params.b}} \} \)</p>
        <p>
          Determine the size of the union of sets \( A \) and \( B \), denoted as
          \( |A \cup B| \).
        </p>
      </pl-question-panel>
      <pl-integer-input
        answers-name="c"
        label="Size of \( |A \cup B| \) ="
      ></pl-integer-input>
      
    • server.py:

      import random
      from sympy import FiniteSet, Union
      def generate(data):
          # Sample two random sets with integers between 1 and 20
          a = random.sample(range(1, 21), random.randint(3, 7))
          b = random.sample(range(1, 21), random.randint(3, 7))
          A = FiniteSet(*a)
          B = FiniteSet(*b)
      
          # Calculate the union of the two sets
          C = Union(A, B)
      
          # Store the sets and the size of their union in the data dictionary
          data['params']['a'] = ', '.join(map(str, a))
          data['params']['b'] = ', '.join(map(str, b))
          data['correct_answers']['c'] = len(C)
      
  3. Read through these files carefully and refer to the question authoring documentation to understand how the question works:

    • The info.json file contains metadata about the question, like its unique ID, title, topic, tags, and type.
    • The question.html file defines the structure of the question using HTML and PrairieLearn elements. It displays the two sets A and B using parameters generated in server.py, and includes an integer input element for the student’s answer.
    • The server.py file randomly generates the sets A and B, calculates the correct answer (size of the union), and stores these in the data dictionary for use in the question.
  4. Repeat this process with other questions in the course to get a feel for different question types, elements, and grading methods used. The exampleCourse directory in the PrairieLearn repository is also a great resource to explore.

Learning to Author Questions

  1. Explore the existing questions for the course on the PrairieLearn website.
  2. For each question, find its corresponding source code in the cloned course repository. Question files are located in questions/ or subdirectories.
  3. Read through the info.json, question.html, and server.py files to understand how the question is structured and generated.
    • info.json contains metadata about the question like its UUID, title, topic, tags
    • question.html has the question prompt and defines the elements for displaying and answering
    • server.py randomly generates question parameters, calculates the correct answer, and performs grading
  4. Consult the detailed documentation on authoring questions: https://prairielearn.readthedocs.io/en/latest/question/
  5. Experiment with creating your own questions by modifying existing ones or authoring from scratch. The exampleCourse/questions directory has some templates to start from.

Selecting Question Ideas and Implementing Them

  1. Review the list of question ideas shared by Arpan. Think about additional topics or concepts where you could create practice questions.
  2. Select a question idea to implement and draft out the structure:
    • What randomized parameters will the question have?
    • How will the correct answer be calculated?
    • What elements will you use for the question display and answer input?
  3. Create a new directory for your question under questions/ in the course repository.
  4. Implement your question locally, creating the necessary info.json, question.html, and server.py files.
  5. Test your question thoroughly locally to ensure it behaves as expected.
  6. When your question is ready, push your changes to GitHub and create a pull request for review.
  7. Respond to any feedback and iterate on your question until it is ready to be merged and deployed.

Best Practices and Tips

  • Use the built-in PrairieLearn elements for answer input and display whenever possible.
  • Follow best practices for custom grading functions as outlined in the docs:
    • Store the correct answer in data["correct_answers"][var_name] in server.py.
    • For custom grading, set data["score"] to the total score (0 to 1) and store individual component scores and feedback in data["partial_scores"][var_name]["score"] and data["partial_scores"][var_name]["feedback"].
    • Use math.isclose() or the is_correct_scalar_ functions from prairielearn.py to compare floats, not exact equality.
    • Always cast submitted answers to the desired data type.
  • Be mindful of how you display and round numerical parameters. Generate the correct answer using the same rounded values shown to the student.
  • Start simple and incrementally add complexity and randomization to your questions.
  • Ask for feedback early and often as you’re developing questions.

Appendix / Additional Suggestions

  • Skim the Workshop section of the docs to gain a high-level understanding of PrairieLearn: https://prairielearn.readthedocs.io/en/latest/workshop/
  • Explore the example course at PrairieLearn/exampleCourse to see a wide variety of question types and elements
  • Don’t get discouraged, authoring good questions takes time and practice! Start simple and slowly build in randomization and complexity. Don’t hesitate to ask for feedback.