Skip to content

Commit

Permalink
Message templates allowed in basic core functions
Browse files Browse the repository at this point in the history
  • Loading branch information
acbart committed Mar 19, 2024
1 parent 0781a00 commit 2a1d465
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 21 deletions.
4 changes: 4 additions & 0 deletions change_log.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Version 2.6.1 (3/19/2024)
-------------------------
* The explain, gently, guidance, and compliment functions can now take `message_template` as a keyword parameter INSTEAD of `message`

Version 2.6.0 (3/16/2024)
-------------------------
* Allow unit_test to be used as a context manager
Expand Down
20 changes: 16 additions & 4 deletions docsrc/teachers/tools/core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,31 @@ Imported as::

Set this submission as correct/complete/successful. Typically resolved as overriding
all other feedback. Often triggered as part of a conditional. You can optionally set
an (internal) `justification` message for why this was triggered.
an (internal) ``justification`` message for why this was triggered.

::

set_success()

.. function:: compliment(message: str, value: float = 0, justification: str = None)
compliment(message_template: str, fields=dict)

Provides a `message` to the student complimenting them on something they did correctly.
You can also specify a numeric `value` that will be added as partial credit.
Finally, you can optionally set an internal `justification` message for why this was triggered.
Provides a ``message`` to the student complimenting them on something they did correctly.
You can also specify a numeric ``value`` that will be added as partial credit.
Finally, you can optionally set an internal ``justification`` message for why this was triggered.

::

compliment("Your `for` loop looks correct!")

If you provide a ``message_template`` keyword parameter instead of a ``message``, you can have fields
with proper formatting. Fields can either be provided explicitly as a dictionary, or as additional keyword
arguments (assuming they do not overlap with any Feedback Function parameters).

::

compliment(message_template="Hello {name:python_code}!", fields={"name": "Ada"})

.. function:: give_partial(value: float, justification: str = None)

Increases the student's overall score by the numeric `value`.
Expand All @@ -35,6 +44,7 @@ Imported as::
give_partial(.5)

.. function:: explain(message: str, label: str = "explain", justification: str = None)
explain(message_template: str, fields: dict)

A core feedback function, used to display a specific feedback `message` response to the
learner. The `label` can be given to help track this piece of feedback; we strongly recommend
Expand All @@ -49,6 +59,7 @@ Imported as::
explain("You need to use a For loop for this problem!", label="do_not_use_for_loop")

.. function:: gently(message: str, label: str, justification: str = None)
gently(message_template: str, fields: dict)

A core feedback function, used to display a specific feedback `message` to the learner.
Basically the same as the :py:func:`explain`, except the priority is much lower. This will not
Expand All @@ -65,6 +76,7 @@ Imported as::
label="need_multiplication")

.. function:: guidance(message: str, label: str = "guidance", justification: str = None)
guidance(message_template: str, fields: dict)

Used to display guiding feedback such as a hint or revised instructions via the `message` to the learner.
You are recommended to include a :term:`Feedback Label`, but not obligated. You can also optionally
Expand Down
24 changes: 16 additions & 8 deletions pedal/core/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ class compliment(FeedbackResponse):
valence = Feedback.POSITIVE_VALENCE
correct = True

def __init__(self, message, title=None, **kwargs):
def __init__(self, message=None, title=None, message_template=None, **kwargs):
if title is None:
title = message
super().__init__(message=message, title=title, **kwargs)
if message is None and message_template is None:
raise ValueError("compliment requires at least either message or message_template")
super().__init__(message=message, title=title, message_template=message_template, **kwargs)


class give_partial(FeedbackResponse):
Expand All @@ -77,8 +79,10 @@ class explain(FeedbackResponse):
kind = FeedbackKind.MISTAKE
valence = Feedback.NEGATIVE_VALENCE

def __init__(self, message, **kwargs):
super().__init__(message=message, **kwargs)
def __init__(self, message=None, message_template=None, **kwargs):
if message is None and message_template is None:
raise ValueError("explain requires at least either message or message_template")
super().__init__(message=message, message_template=message_template, **kwargs)


class gently(FeedbackResponse):
Expand All @@ -96,8 +100,10 @@ class gently(FeedbackResponse):
kind = FeedbackKind.MISTAKE
valence = Feedback.NEGATIVE_VALENCE

def __init__(self, message, **kwargs):
super().__init__(message=message, **kwargs)
def __init__(self, message=None, message_template=None, **kwargs):
if message is None and message_template is None:
raise ValueError("gently requires at least either message or message_template")
super().__init__(message=message, message_template=message_template, **kwargs)


class guidance(FeedbackResponse):
Expand All @@ -107,8 +113,10 @@ class guidance(FeedbackResponse):
kind = FeedbackKind.INSTRUCTIONAL
valence = Feedback.NEUTRAL_VALENCE

def __init__(self, message, **kwargs):
super().__init__(message=message, **kwargs)
def __init__(self, message=None, message_template=None, **kwargs):
if message is None and message_template is None:
raise ValueError("compliment requires at least either message or message_template")
super().__init__(message=message, message_template=message_template, **kwargs)


def hide_correctness(report=MAIN_REPORT):
Expand Down
44 changes: 35 additions & 9 deletions tests/test_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,54 @@
from pedal.resolvers import simple


class CustomFormatter(Formatter):
def name(self, value):
return f"<code>{value}</code>"

def line(self, line_number):
return f"<a href=''>{line_number}</a>"


class TestCode(unittest.TestCase):

def test_custom_formatter(self):
clear_report()

class CustomFormatter(Formatter):
def name(self, value):
return f"<code>{value}</code>"
def line(self, line_number):
return f"<a href=''>{line_number}</a>"

contextualize_report(Submission(main_code="alpha=0"))
set_formatter(CustomFormatter)
tifa_analysis()

if get_all_feedback():
print(get_all_feedback()[0].message)
#if get_all_feedback():
# print(get_all_feedback()[0].message)

final = simple.resolve()
self.assertEqual(final.message,
"The variable <code>alpha</code> was given a value on line <a href=''>1</a>, but was never used after that.")


class TestMessageTemplateInCore(unittest.TestCase):

def test_gently_fields(self):
clear_report()

contextualize_report(Submission(main_code="alpha=0"))
set_formatter(CustomFormatter)
gently(message_template="This {where:line} should get formatted.",
fields={"where": 27})

final = simple.resolve()
self.assertEqual(final.message, "This <a href=''>27</a> should get formatted.")

def test_gently_fields_implicit(self):
clear_report()

contextualize_report(Submission(main_code="alpha=0"))
set_formatter(CustomFormatter)
gently(message_template="This {where:line} should get formatted.",
where=27)

final = simple.resolve()
self.assertEqual(final.message, "This <a href=''>27</a> should get formatted.")


if __name__ == '__main__':
unittest.main(buffer=False)

0 comments on commit 2a1d465

Please sign in to comment.