Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

requester.request json keyword doesn't allow for actual json inputs #668

Open
dsavransky opened this issue Sep 25, 2024 · 0 comments
Open
Labels

Comments

@dsavransky
Copy link
Contributor

Describe the bug

I'm working with the new quiz items API (https://canvas.instructure.com/doc/api/new_quiz_items.html) and have run into an issue where it appears that the structure of canvasapi's request class is incompatible with this endpoint.

Specifically, the scoring_data dictionary for the multiple choice with varying point values by answer item type (https://canvas.instructure.com/doc/api/new_quiz_items.html#choice) requires an internal list of dictionaries, e.g.:

"scoring_data": {
    "value": "f1feae62-566d-4d85-9afb-182d757030c9",
    "values": [
        {
            "value": "f1feae62-566d-4d85-9afb-182d757030c9",
            "points": 2
        },
        {
            "value": "22d2bd84-5d5a-4640-8acf-484d799a735a",
            "points": 1
        },
        {
            "value": "74a22711-85a6-4b46-8fb3-ea22947e869a",
            "points": 0
        },
        {
            "value": "3ae2c63d-b990-40f0-aa70-e6bb854d0de2",
            "points": 0
        },
        {
            "value": "8193a348-d336-4b00-b60e-dece48739ce4",
            "points": 0
        }
    ]
}

If you run this through combine_kwargs you'll get something like:

[('item[scoring_data][value]', 'f1feae62-566d-4d85-9afb-182d757030c9'),
 ('item[scoring_data][values][][value]',
  'f1feae62-566d-4d85-9afb-182d757030c9'),
 ('item[scoring_data][values][][points]', 2),
 ('item[scoring_data][values][][value]',
  '22d2bd84-5d5a-4640-8acf-484d799a735a'),
 ('item[scoring_data][values][][points]', 1),
 ('item[scoring_data][values][][value]',
  '74a22711-85a6-4b46-8fb3-ea22947e869a'),
 ('item[scoring_data][values][][points]', 0),
 ('item[scoring_data][values][][value]',
  '3ae2c63d-b990-40f0-aa70-e6bb854d0de2'),
 ('item[scoring_data][values][][points]', 0),
 ('item[scoring_data][values][][value]',
  '8193a348-d336-4b00-b60e-dece48739ce4'),
 ('item[scoring_data][values][][points]', 0)]

Trying to then PUT this data up to Canvas will generate the error:
UnprocessableEntity: {"errors":{"scoring_data":["Invalid Scoring Data: The property '#/values/0/points' of type string did not match the following type: number"]},"message":"Unprocessable Entity"}

This seems to be a case where it is much simpler to just send a dictionary directly, and I see that the request method has a json keyword, but it looks like setting this to True, doesn't actually allow you to send a data dictionary as _kwargs is still expected to be a list of tuples. Is there any way to make this work with the canvasapi requester, or is this a case where just manually assembling the request is the best way to go?

To Reproduce

Minimal worked example:

#course is a canvasapi course object

nq = course.create_new_quiz(
    quiz={
        "title": "Quiz Example",
        "assignment_group_id": xxxxxx,
        "points_possible": 10,
        "grading_type": "points",
        "instructions": "something"})

item = {
    "position": 1,
    "points_possible": 3.0,
    "entry_type": "Item",
    "status": "immutable",
    "entry": {
        "title": "Q1",
        "item_body": "<p>Answer the question</p>",
        "calculator_type": "none",
        "interaction_data": {
            "choices": [
                {
                    "id": "e5519152-c925-4abd-a0ec-3081511ca636",
                    "position": 1,
                    "item_body": "<p>0</p>",
                },
                {
                    "id": "3f55f6d8-7115-4d5b-bb70-07e15bb76112",
                    "position": 2,
                    "item_body": "<p>1</p>",
                },
                {
                    "id": "7d243ebc-cff9-4b97-b047-b96d0b8e2aed",
                    "position": 3,
                    "item_body": "<p>2</p>",
                },
                {
                    "id": "ff4cc47b-1846-4e7f-8482-b471685f8865",
                    "position": 4,
                    "item_body": "<p>3</p>",
                },
            ]
        },
        "properties": {
            "shuffle_rules": {"choices": {"to_lock": [], "shuffled": False}},
            "vary_points_by_answer": True,
        },
        "scoring_data": {
            "value": "ff4cc47b-1846-4e7f-8482-b471685f8865",
            "values": [
                {"value": "e5519152-c925-4abd-a0ec-3081511ca636", "points": 0},
                {"value": "3f55f6d8-7115-4d5b-bb70-07e15bb76112", "points": 1},
                {"value": "7d243ebc-cff9-4b97-b047-b96d0b8e2aed", "points": 2},
                {"value": "ff4cc47b-1846-4e7f-8482-b471685f8865", "points": 3},
            ],
        },
        "answer_feedback": {"e5519152-c925-4abd-a0ec-3081511ca636": ""},
        "scoring_algorithm": "VaryPointsByAnswer",
        "interaction_type_slug": "choice",
        "feedback": {},
    },
}

endpoint = "courses/{}/quizzes/{}/items".format(course.id, nq.id)

# this leads to Canvas error:
r =nq._requester.request(
            "POST",
            endpoint,
            _url="new_quizzes",
            _kwargs=combine_kwargs(**{"item":item}),
        )

#setting json=True leads to different error: BadRequest: {"error":"Expected `item` object"}

Expected behavior

Setting up the request manually works as expected:

full_url = "{}{}".format(
    course._requester.new_quizzes_url,
    "courses/{}/quizzes/{}/items".format(course.id, nq.id),
)
headers = {"Authorization": "Bearer {}".format(course._requester.access_token)}
r = requests.post(full_url, json={"item": tmp}, headers=headers)

Environment information

  • Python 3.11.9
  • CanvasAPI version 3.3.0

Additional context

Thanks!

@dsavransky dsavransky added the bug label Sep 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant