-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨(models) add peer instruction events pydantic models
Peer instruction events are emitted by the server to capture information about peer instruction XBlock.
- Loading branch information
Showing
9 changed files
with
211 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# noqa: D104 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# noqa: D104 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
"""Peer instruction event field definition.""" | ||
|
||
from pydantic import constr | ||
|
||
from ...base import AbstractBaseEventField | ||
|
||
|
||
class PeerInstructionEventField(AbstractBaseEventField): | ||
"""Pydantic model for peer instruction `event` field. | ||
Attributes: | ||
answer (int): Consists of the index assigned to the answer choice selected by | ||
the learner. | ||
rationale (str): Consists of the text entered by the learner to explain why | ||
they selected that answer choice. | ||
truncated (bool): `True` only if the rationale was longer than 12,500 | ||
characters, which is the maximum included in the event. | ||
""" | ||
|
||
answer: int | ||
rationale: constr(max_length=12500) | ||
truncated: bool |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
"""Peer instruction events model definitions.""" | ||
|
||
from typing import Union | ||
|
||
try: | ||
from typing import Literal | ||
except ImportError: | ||
from typing_extensions import Literal | ||
|
||
from pydantic import Json | ||
|
||
from ralph.models.selector import selector | ||
|
||
from ..server import BaseServerModel | ||
from .fields.events import PeerInstructionEventField | ||
|
||
|
||
class PeerInstructionAccessed(BaseServerModel): | ||
"""Pydantic model for `ubc.peer_instruction.accessed` statement. | ||
The server emits this event when a peer instruction question and its set of answer | ||
choices is shown to a learner. | ||
Attributes: | ||
event_type (str): Consists of the value `ubc.peer_instruction.accessed`. | ||
name (str): Consists of the value `ubc.peer_instruction.accessed`. | ||
""" | ||
|
||
__selector__ = selector( | ||
event_source="server", event_type="ubc.peer_instruction.accessed" | ||
) | ||
|
||
event_type: Literal["ubc.peer_instruction.accessed"] | ||
name: Literal["ubc.peer_instruction.accessed"] | ||
|
||
|
||
class PeerInstructionOriginalSubmitted(BaseServerModel): | ||
"""Pydantic model for `ubc.peer_instruction.original_submitted` statement. | ||
The server emits this event when learners submit their initial responses. These | ||
events record the answer choice the learner selected and the explanation given | ||
for why that selection was made. | ||
Attributes: | ||
event (int): See PeerInstructionEventField. | ||
event_type (str): Consists of the value | ||
`ubc.peer_instruction.original_submitted`. | ||
name (str): Consists of the value `ubc.peer_instruction.original_submitted`. | ||
""" | ||
|
||
__selector__ = selector( | ||
event_source="server", event_type="ubc.peer_instruction.original_submitted" | ||
) | ||
|
||
event: Union[ | ||
Json[PeerInstructionEventField], # pylint: disable=unsubscriptable-object | ||
PeerInstructionEventField, | ||
] | ||
event_type: Literal["ubc.peer_instruction.original_submitted"] | ||
name: Literal["ubc.peer_instruction.original_submitted"] | ||
|
||
|
||
class PeerInstructionRevisedSubmitted(BaseServerModel): | ||
"""Pydantic model for `ubc.peer_instruction.revised_submitted` statement. | ||
The server emits this event when learners submit their revised responses. These | ||
events record the answer choice selected by the learner and the explanation for | ||
why that selection was made. | ||
Attributes: | ||
event (int): See PeerInstructionEventField. | ||
event_type (str): Consists of the value | ||
`ubc.peer_instruction.revised_submitted`. | ||
name (str): Consists of the value `ubc.peer_instruction.revised_submitted`. | ||
""" | ||
|
||
__selector__ = selector( | ||
event_source="server", event_type="ubc.peer_instruction.revised_submitted" | ||
) | ||
|
||
event: Union[ | ||
Json[PeerInstructionEventField], # pylint: disable=unsubscriptable-object | ||
PeerInstructionEventField, | ||
] | ||
event_type: Literal["ubc.peer_instruction.revised_submitted"] | ||
name: Literal["ubc.peer_instruction.revised_submitted"] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
"""Tests for peer instruction models event fields.""" | ||
|
||
import json | ||
|
||
import pytest | ||
from pydantic.error_wrappers import ValidationError | ||
|
||
from ralph.models.edx.peer_instruction.fields.events import PeerInstructionEventField | ||
|
||
from tests.fixtures.hypothesis_strategies import custom_given | ||
|
||
|
||
@custom_given(PeerInstructionEventField) | ||
def test_models_edx_peer_instruction_event_field_with_valid_field(field): | ||
"""Tests that a valid `PeerInstructionEventField` does not raise a | ||
`ValidationError`. | ||
""" | ||
assert len(field.rationale) <= 12500 | ||
|
||
|
||
@custom_given(PeerInstructionEventField) | ||
def test_models_edx_peer_instruction_event_field_with_invalid_rationale(field): | ||
"""Tests that a valid `PeerInstructionEventField` does not raise a | ||
`ValidationError`. | ||
""" | ||
invalid_field = json.loads(field.json()) | ||
invalid_field["rationale"] = "x" * 12501 | ||
with pytest.raises( | ||
ValidationError, | ||
match="rationale\n ensure this value has at most 12500 characters", | ||
): | ||
PeerInstructionEventField(**invalid_field) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
"""Tests for the peer_instruction event models.""" | ||
|
||
import json | ||
|
||
import pytest | ||
from hypothesis import strategies as st | ||
|
||
from ralph.models.edx.peer_instruction.statements import ( | ||
PeerInstructionAccessed, | ||
PeerInstructionOriginalSubmitted, | ||
PeerInstructionRevisedSubmitted, | ||
) | ||
from ralph.models.selector import ModelSelector | ||
|
||
from tests.fixtures.hypothesis_strategies import custom_builds, custom_given | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"class_", | ||
[ | ||
PeerInstructionAccessed, | ||
PeerInstructionOriginalSubmitted, | ||
PeerInstructionRevisedSubmitted, | ||
], | ||
) | ||
@custom_given(st.data()) | ||
def test_models_edx_peer_instruction_selectors_with_valid_statements(class_, data): | ||
"""Tests given a valid peer_instruction edX statement the `get_first_model` | ||
selector method should return the expected model. | ||
""" | ||
statement = json.loads(data.draw(custom_builds(class_)).json()) | ||
model = ModelSelector(module="ralph.models.edx").get_first_model(statement) | ||
assert model is class_ | ||
|
||
|
||
@custom_given(PeerInstructionAccessed) | ||
def test_models_edx_peer_instruction_accessed_with_valid_statement( | ||
statement, | ||
): | ||
"""Tests that a `ubc.peer_instruction.accessed` statement has the expected | ||
`event_type`.""" | ||
assert statement.event_type == "ubc.peer_instruction.accessed" | ||
assert statement.name == "ubc.peer_instruction.accessed" | ||
|
||
|
||
@custom_given(PeerInstructionOriginalSubmitted) | ||
def test_models_edx_peer_instruction_original_submitted_with_valid_statement( | ||
statement, | ||
): | ||
"""Tests that a `ubc.peer_instruction.original_submitted` statement has the | ||
expected `event_type`.""" | ||
assert statement.event_type == "ubc.peer_instruction.original_submitted" | ||
assert statement.name == "ubc.peer_instruction.original_submitted" | ||
|
||
|
||
@custom_given(PeerInstructionRevisedSubmitted) | ||
def test_models_edx_peer_instruction_revised_submitted_with_valid_statement( | ||
statement, | ||
): | ||
"""Tests that a `ubc.peer_instruction.revised_submitted` statement has the | ||
expected `event_type`.""" | ||
assert statement.event_type == "ubc.peer_instruction.revised_submitted" | ||
assert statement.name == "ubc.peer_instruction.revised_submitted" |