In this article, we will show you how to retrieve open-question responses for a specific assignment using a Python script and export them to a CSV file.
We will walk you through the script construction, explaining the requirements, setup, the Ans API endpoints you need to use, and the exact steps to follow.
By the end, you'll have a clear understanding of how to write a Python script that interacts with the Ans API and how to save the retrieved data to a CSV file.
Step 1: Set Up the Environment
Before you begin, you need to set up the environment with some basic dependencies.
Libraries Required:
-
csv: A built-in Python library used to write data into CSV files.
-
os: A built-in Python library used to access environment variables, which help securely handle API tokens and domain names.
-
requests: An external library used to make HTTP requests (such as GET requests) to an API. Install it using
pip install requests
if it’s not already installed.
Environment Variables:
Environment variables are settings that programs can read to configure how they behave. They also help ensure safe and efficient program execution. In this guide, we’ll be using two environment variables to store your information securely:
-
TOKEN: Your unique API key connected to your Ans account. You can find your API token by following the steps described in this article: Create API token.
-
DOMAIN: Specifies which Ans environment you'd like to use. This can be either
https://ans.app
,https://stage.ans.app
, or a custom domain if you have that option enabled for your school.
error_outlineFor security reasons, we strongly recommend storing sensitive information like the TOKEN in environment variables.
error_outlineSteps to set up environment variables may differ depending on your operational system (Windows, Mac, etc), type of program or cloud environment (AWS, Google Collab, etc). Please investigate how to set up environment variables specific to your situation.
Assignment ID:
Finally, you need to provide the ID of the assignment you want to export (referred to as assignment_id
in the script).
Step 2: Create the Client
class
The main functionality of this script is handled within the Client
class. Let's break down the class and its methods.
2.1. __init__
Method: Initialize the API client
-
The
__init__
method initializes the class by setting theDOMAIN
andTOKEN
attributes from environment variables. If they are not set, default values are provided. - In the example above, default values are presented as
'https://example.com'
and'your-api-token-here'
. - While testing, you can use replace default values with your
DOMAIN
andTOKEN
to make testing easier. This is not necessary if you're using environment variables while testing.
error_outlineIt's strongly recommended not to use default values if you're planning on using the script with real production data. Please use environment variables instead.
2.2. headers
Method: Generate authorization headers
-
This method returns the headers needed to authenticate the API requests. It uses the
TOKEN
stored in the class to generate aBearer
token for authorization.
2.3. request
Method: Perform an API request
-
This method performs a
GET
request to a specified APIendpoint
. It constructs the full URL by appending theendpoint
to theDOMAIN
. -
The
raise_for_status
method ensures that any error (e.g., 404, 500) raises an exception. -
The method returns the JSON response.
2.4. API methods to retrieve data
These methods interact with specific parts of the API to fetch relevant data.
get_exercises
Method
-
This method retrieves all exercises for a given assignment. The
assignment_id
is passed as a parameter, and the method constructs the appropriate endpoint (/api/v2/assignments/{assignment_id}/exercises
) to make a request.
get_questions
Method
-
This method retrieves all questions for a given exercise. The
exercise_id
is passed as a parameter, and the appropriate API endpoint (/api/v2/exercises/{exercise_id}/questions
) is used to fetch the questions.
get_open_question_ids
Method: filter for open questions
-
This method finds all open-ended question IDs for a given assignment.
-
It calls
get_exercises(assignment_id)
to get all exercises for the assignment, then loops through each exercise and uses theget_questions(exercise['id'])
method to fetch the questions associated with each exercise. -
The method filters questions by checking if their category is
"open"
, and if so, it appends their ID to thequestion_ids
list. -
Finally, it returns a list of the open question IDs.
get_results
Method
-
This method retrieves the results for a specific assignment. The
assignment_id
is used to construct the API endpoint/api/v2/assignments/{assignment_id}/results
.
get_result
Method
-
This method retrieves detailed information for a specific result. The
result_id
is passed to the method, which constructs the endpoint/api/v2/results/{result_id}
to retrieve the data.
get_submission
Method
-
This method retrieves detailed information for a specific submission. The
submission_id
is passed to the method, which constructs the endpoint/api/v2/submissions/{submission_id}
to fetch submission details.
get_user
Method
-
This method retrieves information about a specific user based on their
user_id
. It constructs the endpoint/api/v2/users/{user_id}
to fetch user details like their first name, last name, and student number.
Step 3: Export data to CSV
The method export_to_csv
is responsible for exporting the retrieved data into a CSV file.
3.1. Set up CSV file
-
The method starts by calling
get_open_question_ids(assignment_id)
to retrieve the IDs of the open-ended questions. -
A CSV file is opened for writing, and the header row is created with columns for the student number, first name, last name, and one column for each open question.
3.2. Iterate over results and write data
-
The method loops through all results of the assignment, retrieving user details (student number, first name, last name).
-
It then loops through each result's submissions and collects answers for the open-ended questions. The responses are stored in the order of the open question IDs.
-
The responses for each submission are joined into a single string, separated by semicolons if there are multiple answers.
-
Each row (student and their answers) is written into the CSV file.
3.3. Finalize the export
- Once all rows are written, the process is finished and a CSV file is saved automatically. It will have the file name provided in step 3.1.
-
A success message is printed indicating that the CSV file has been created.
3.4. Where to Place the Script?
You can put the script in any folder on your local machine. Here’s a simple approach:
-
Create a folder for the script:
-
On Windows: Open PowerShell or Command Prompt and run:
-
On macOS/Linux: Open the terminal and run:
-
- 💡 TIP: You can create a folder in any way you prefer. The examples above simply describe how to do it through the console.
-
Create a text file inside that folder and copy-paste the script into the file
-
Save this file in your folder and name it
export_ans_csv.py
.
3.5 How to Test the Script?
Once the script is saved, go to your console and run the following commands:
This will prompt you to enter an Assignment ID, fetch the data, and generate the CSV.
-
After running the script, check the folder where the script is located.
-
Open
export.csv
in a spreadsheet program (Excel, Google Sheets) to verify that the data is correctly formatted.
Step 4: Final script
Here you can see an example of what the entire script looks like.
import csv
import os
from requests import get
class Client:
def __init__(self):
self.DOMAIN = os.environ.get('DOMAIN', 'https://example.com')
self.TOKEN = os.environ.get('TOKEN', 'your-api-token-here')
def headers(self):
return {"Authorization": f"Bearer {self.TOKEN}"}
def request(self, endpoint):
"""Performs a GET request to the given API endpoint."""
url = f"{self.DOMAIN}{endpoint}"
response = get(url, headers=self.headers())
response.raise_for_status()
return response.json()
def get_exercises(self, assignment_id):
return self.request(f"/api/v2/assignments/{assignment_id}/exercises")
def get_questions(self, exercise_id):
return self.request(f"/api/v2/exercises/{exercise_id}/questions")
def get_open_question_ids(self, assignment_id):
question_ids = []
exercises = self.get_exercises(assignment_id)
for exercise in exercises:
for question in self.get_questions(exercise['id']):
if question['category'] == 'open':
question_ids.append(question['id'])
return question_ids
def get_results(self, assignment_id):
return self.request(f"/api/v2/assignments/{assignment_id}/results")
def get_result(self, result_id):
return self.request(f"/api/v2/results/{result_id}")
def get_submission(self, submission_id):
return self.request(f"/api/v2/submissions/{submission_id}")
def get_user(self, user_id):
return self.request(f"/api/v2/users/{user_id}")
def export_to_csv(self, assignment_id, filename="export.csv"):
open_question_ids = self.get_open_question_ids(assignment_id)
with open(filename, mode='w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
# Create a header row for the CSV file
headers = ["Student Number", "First Name", "Last Name"]
headers += [f"Question {i+1}" for i in range(len(open_question_ids))]
writer.writerow(headers)
for result in self.get_results(assignment_id):
user_info = self.get_user(result['user_id'])
row = [user_info['student_number'], user_info['first_name'], user_info['last_name']]
# Collect responses for open questions
result_details = self.get_result(result['id'])
responses = ["" for _ in open_question_ids]
for submission in result_details['submissions']:
if submission['question_id'] in open_question_ids:
response_content = [r['content'] for r in self.get_submission(submission['id'])['responses']]
responses[open_question_ids.index(submission['question_id'])] = "; ".join(response_content)
# Append responses in order
row += responses
writer.writerow(row)
print(f"CSV file '{filename}' created successfully.")
# Only required if you wish to run the script manually
# Gives you a way to type in an assignment ID
if __name__ == "__main__":
assignment_id = input("Enter Assignment ID: ")
client = Client()
client.export_to_csv(assignment_id)
Comments
0 comments
Please sign in to leave a comment.