Repository: ucbds-infra/otter-grader

Issue:
Add option to get results pickle file to otter run
As titled

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 363a1a06..1da40d33 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
 * Added backwards compatibility to Otter Grade for autograder configuration zip files generated in previous major versions of Otter-Grader
 * Add `gcc_linux-64` and `gxx_linux-64` to R grading image dependencies per [#819](https://github.com/ucbds-infra/otter-grader/issues/819)
 * Fixed a bug where the loop variable used in Otter's generated grading code overwrote variables defined by the notebook per [#817](https://github.com/ucbds-infra/otter-grader/issues/817)
+* Add `--pickle-results` option to Otter Run to output the results pickle file per [#818](https://github.com/ucbds-infra/otter-grader/issues/818)
 
 **v5.5.0:**
 
diff --git a/otter/cli.py b/otter/cli.py
index 14118ebd..105568cc 100644
--- a/otter/cli.py
+++ b/otter/cli.py
@@ -160,8 +160,15 @@ defaults = run.__kwdefaults__
 @click.option("-o", "--output-dir", default=defaults["output_dir"], type=click.Path(exists=True, file_okay=False), help="Directory to which to write output")
 @click.option("--no-logo", is_flag=True, help="Suppress Otter logo in stdout")
 @click.option("--debug", is_flag=True, help="Do not ignore errors when running submission")
+@click.option("-p", "--pickle-results", is_flag=True, help="Output GradingResults pickle file")
 def run_cli(*args, **kwargs):
     """
-    Run non-containerized Otter on a single submission.
+    Run non-containerized Otter on a single submission, writing results to a JSON file.
     """
-    return run(*args, **kwargs)
+    write_pkl = kwargs.pop("pickle_results", False)
+    results = run(*args, **kwargs)
+    if write_pkl:
+        import dill
+        with open("results.pkl", "wb+") as f:
+            dill.dump(results, f)
+    return results


Test patch:
diff --git a/test/test_cli.py b/test/test_cli.py
index 2d7cde91..44b2ebb5 100644
--- a/test/test_cli.py
+++ b/test/test_cli.py
@@ -1,5 +1,6 @@
 """Tests for ``otter.cli``"""
 
+import dill
 import logging
 import os
 import pytest
@@ -12,6 +13,7 @@ from otter.cli import cli
 from otter.generate import main as generate
 from otter.grade import _ALLOWED_EXTENSIONS, main as grade
 from otter.run import main as run
+from otter.test_files import GradingResults
 
 
 def assert_cli_result(result, expect_error):
@@ -531,6 +533,8 @@ def test_run(mocked_run, run_cli):
     open("foo.ipynb", "w+").close()
     open("autograder.zip", "wb+").close()
 
+    mocked_run.return_value = GradingResults([])
+
     std_kwargs = dict(
         submission="foo.ipynb",
         **run.__kwdefaults__,
@@ -549,6 +553,14 @@ def test_run(mocked_run, run_cli):
     assert_cli_result(result, expect_error=False)
     mocked_run.assert_called_with(**{**std_kwargs, "autograder": "foo.zip"})
 
+    result = run_cli([*cmd_start, "--pickle-results"])
+    assert_cli_result(result, expect_error=False)
+    mocked_run.assert_called_with(**std_kwargs)
+    assert os.path.isfile("results.pkl")
+    with open("results.pkl", "rb") as f:
+        gr = dill.load(f)
+    assert isinstance(gr, GradingResults)
+
     os.mkdir("out")
     result = run_cli([*cmd_start, "-o", "out"])
     assert_cli_result(result, expect_error=False)