Repository: microsoft/pybryt

Issue:
Make `check` context accept an annotation group parameter
`StudentImplementation`s and `ReferenceImplementation`s support checking specific groups of annotations in a single reference using a `group` parameter. This feature should be added to the `check` context.

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 82de47d..2eee6ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file, and this pr
 * Added `TimeComplexityChecker` for analyzing complexity without annotations per [#137](https://github.com/microsoft/pybryt/issues/137)
 * Fixed annotation message filtering bug per [#145](https://github.com/microsoft/pybryt/issues/145)
 * Added `dataclasses` backport to required modules for Python &lt; 3.7
+* Added a `group` argument to the `check` context manager per [#146](https://github.com/microsoft/pybryt/issues/146)
 
 ## 0.3.1 - 2021-12-01
 
diff --git a/pybryt/student.py b/pybryt/student.py
index ba56688..b0067dd 100644
--- a/pybryt/student.py
+++ b/pybryt/student.py
@@ -310,9 +310,10 @@ class check:
     Args:
         ref (``Union[str, ReferenceImplementation, list[str], list[ReferenceImplementation]]``): the
             reference(s) to check against or the path(s) to them
+        group (``str``, optional): the name of the group of annotations to run in each reference
         report_on_error (``bool``, optional): whether to print the report when an error is thrown
             by the block
-        show_only (one of ``{'satisified', 'unsatisfied', None}``, optional): which types of
+        show_only (one of ``{'satisfied', 'unsatisfied', None}``, optional): which types of
             reference results to include in the report; if ``None``, all are included
         **kwargs: additional keyword arguments passed to ``pybryt.execution.create_collector``
     """
@@ -320,11 +321,14 @@ class check:
     _ref: List[ReferenceImplementation]
     """the references being checked against"""
 
+    _group: Optional[str]
+    """the group of annotations in the references to run"""
+
     _report_on_error: bool
     """whether to print the report when an error is thrown by the block"""
 
     _show_only: Optional[str]
-    """which types of eference results to include in the report"""
+    """which types of reference results to include in the report"""
 
     _frame_tracer: Optional[FrameTracer]
     """the frame tracer being used to manage tracing"""
@@ -339,8 +343,13 @@ class check:
     """whether this check is disbaled (because PyBryt is already tracing)"""
 
     def __init__(
-        self, ref: Union[str, ReferenceImplementation, List[str], List[ReferenceImplementation]], 
-        report_on_error: bool = True, show_only: Optional[str] = None, cache: bool = True, **kwargs
+        self,
+        ref: Union[str, ReferenceImplementation, List[str], List[ReferenceImplementation]], 
+        group: Optional[str] = None,
+        report_on_error: bool = True,
+        show_only: Optional[str] = None,
+        cache: bool = True,
+        **kwargs,
     ):
         if isinstance(ref, str):
             ref = ReferenceImplementation.load(ref)
@@ -357,6 +366,7 @@ class check:
             raise TypeError("Invalid values provided for reference(s)")
 
         self._ref = ref
+        self._group = group
         self._kwargs = kwargs
         self._show_only = show_only
         self._report_on_error = report_on_error
@@ -396,7 +406,7 @@ class check:
             if exc_type is None or self._report_on_error:
                 footprint = self._frame_tracer.get_footprint()
                 stu = StudentImplementation.from_footprint(footprint)
-                res = stu.check(self._ref)
+                res = stu.check(self._ref, group=self._group)
                 report = generate_report(res, show_only=self._show_only)
                 if report:
                     print(report)


Test patch:
diff --git a/tests/test_student.py b/tests/test_student.py
index 56983cd..bf904e0 100644
--- a/tests/test_student.py
+++ b/tests/test_student.py
@@ -193,6 +193,17 @@ def test_check_cm(capsys):
         with pytest.raises(TypeError, match="Invalid values in the reference list"):
             check([ref, "path", 1])
 
+        # check by annotation group
+        with mock.patch.object(StudentImplementation, "from_footprint") as mocked_ff, \
+                mock.patch("pybryt.student.FrameTracer"), \
+                mock.patch("pybryt.student.generate_report"):
+            ref = ReferenceImplementation("groups", [])
+            for run_group in ["1", "2", None]:
+                with check(ref, group=run_group):
+                    pass
+
+                mocked_ff.return_value.check.assert_called_with([ref], group=run_group)
+
     # check caching
     with mock.patch("pybryt.student.FrameTracer") as mocked_frame_tracer:
         with mock.patch("pybryt.student.StudentImplementation") as mocked_stu, \