diff --git a/docs/_static/tutorial.zip b/docs/_static/tutorial.zip index d7a073076..4ee668721 100644 Binary files a/docs/_static/tutorial.zip and b/docs/_static/tutorial.zip differ diff --git a/docs/otter_assign/v0/python_notebook_format.rst b/docs/otter_assign/v0/python_notebook_format.rst index 39ceca598..c27dd4bf3 100644 --- a/docs/otter_assign/v0/python_notebook_format.rst +++ b/docs/otter_assign/v0/python_notebook_format.rst @@ -129,7 +129,7 @@ Assign; optionally, you can specify these via the command line with the ``--user .. code-block:: python from otter.generate.token import APIClient - ​print(APIClient.get_token()) + print(APIClient.get_token()) Any configurations in your ``generate`` key will be put into an ``otter_config.json`` and used when running Otter Generate. diff --git a/docs/otter_assign/v1/notebook_format.rst b/docs/otter_assign/v1/notebook_format.rst index 0ccdd1cf7..1cd722327 100644 --- a/docs/otter_assign/v1/notebook_format.rst +++ b/docs/otter_assign/v1/notebook_format.rst @@ -131,7 +131,7 @@ Assign; optionally, you can specify these via the command line with the ``--user .. code-block:: python from otter.generate.token import APIClient - ​print(APIClient.get_token()) + print(APIClient.get_token()) Any configurations in your ``generate`` key will be put into an ``otter_config.json`` and used when running Otter Generate. diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 7a945ea41..efe8c4898 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -44,18 +44,20 @@ Otter Assign on this notebook, run .. code-block:: console - $ otter assign demo.ipynb dist + $ otter assign demo.ipynb dist --v1 Generating views... Generating solutions PDF... Generating autograder zipfile... Running tests... All tests passed! +The use of the ``--v1`` flag indicates that this is an :ref:`Otter Assign format v1 formatted +notebook `. + Otter Assign should create a ``dist`` directory which contains two further subdirectories: ``autograder`` and ``student``. The ``autograder`` directory contains the Gradescope autograder, solutions PDF, and the notebook with solutions. The ``student`` directory contains just the -sanitized student notebook. Both contain a ``tests`` subdirectory that contains tests, but only -``autograder/tests`` has the hidden tests. +sanitized student notebook. .. code-block:: @@ -65,17 +67,9 @@ sanitized student notebook. Both contain a ``tests`` subdirectory that contains │ ├── demo-sol.pdf │ ├── demo.ipynb │ ├── otter_config.json - │ ├── requirements.txt - │ └── tests - │ ├── q1.py - │ ├── q2.py - │ └── q3.py + │ └── requirements.txt └── student - ├── demo.ipynb - └── tests - ├── q1.py - ├── q2.py - └── q3.py + └── demo.ipynb For more information about the configurations for Otter Assign and its output format, see :reF:`otter_assign`. diff --git a/docs/tutorial/demo.ipynb b/docs/tutorial/demo.ipynb index ecda6c44d..6f653b10f 100644 --- a/docs/tutorial/demo.ipynb +++ b/docs/tutorial/demo.ipynb @@ -1,19 +1,19 @@ { "cells": [ { - "cell_type": "markdown", + "cell_type": "raw", "metadata": {}, "source": [ - "```\n", - "BEGIN ASSIGNMENT\n", + "# ASSIGNMENT CONFIG\n", "requirements: requirements.txt\n", "solutions_pdf: true\n", "export_cell:\n", " instructions: \"These are some submission instructions.\"\n", "generate: \n", " pdf: true\n", - " zips: false\n", - "```" + " filtering: true\n", + " pagebreaks: true\n", + " zips: false" ] }, { @@ -38,21 +38,31 @@ "grader = otter.Notebook()" ] }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN QUESTION\n", + "name: q1" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Question 1:** Write a function `square` that returns the square of its argument.\n", - "\n", - "```\n", - "BEGIN QUESTION\n", - "name: q1\n", - "```" + "**Question 1:** Write a function `square` that returns the square of its argument." + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN SOLUTION" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -60,6 +70,20 @@ " return x**2 # SOLUTION" ] }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END SOLUTION" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN TESTS" + ] + }, { "cell_type": "code", "execution_count": 3, @@ -77,7 +101,6 @@ } ], "source": [ - "# TEST\n", "square(1) == 1" ] }, @@ -98,13 +121,12 @@ } ], "source": [ - "# TEST\n", "square(0) == 0" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -113,26 +135,50 @@ "True" ] }, - "execution_count": 7, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# HIDDEN TEST\n", + "# HIDDEN\n", "square(2.5) == 6.25" ] }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END TESTS" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END QUESTION" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN QUESTION\n", + "name: q2" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Question 2:** Write an infinite generator of the Fibonacci sequence `fiberator` that is *not* recursive.\n", - "\n", - "```\n", - "BEGIN QUESTION\n", - "name: q2\n", - "```" + "**Question 2:** Write an infinite generator of the Fibonacci sequence `fiberator` that is *not* recursive." + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN SOLUTION" ] }, { @@ -152,13 +198,26 @@ " # END SOLUTION" ] }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END SOLUTION" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN TESTS" + ] + }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ - "# TEST\n", "f = fiberator()\n", "assert next(f) == 0\n", "assert next(f) == 1" @@ -170,7 +229,7 @@ "metadata": {}, "outputs": [], "source": [ - "# HIDDEN TEST\n", + "# HIDDEN\n", "f = fiberator()\n", "assert next(f) == 0\n", "assert next(f) == 1\n", @@ -183,6 +242,28 @@ "assert next(f) == 21" ] }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END TESTS" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END QUESTION" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN QUESTION\n", + "name: q3" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -199,12 +280,14 @@ "| vanilla | 2 | 2 |\n", "| mint | 1 | 4 |\n", "| mint | 2 | 5 |\n", - "| chocolate | 3 | 5 |\n", - "\n", - "```\n", - "BEGIN QUESTION\n", - "name: q3\n", - "```" + "| chocolate | 3 | 5 |" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN SOLUTION" ] }, { @@ -245,6 +328,20 @@ "price_by_flavor" ] }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END SOLUTION" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN TESTS" + ] + }, { "cell_type": "code", "execution_count": 14, @@ -262,7 +359,6 @@ } ], "source": [ - "# TEST\n", "len(data[\"flavor\"].unique()) == 4" ] }, @@ -272,7 +368,6 @@ "metadata": {}, "outputs": [], "source": [ - "# TEST\n", "for l in [\"chocolate\", \"vanilla\", \"strawberry\", \"mint\"]:\n", " assert l in data[\"flavor\"].unique()" ] @@ -283,7 +378,6 @@ "metadata": {}, "outputs": [], "source": [ - "# TEST\n", "assert type(price_by_flavor) == pd.Series" ] }, @@ -293,7 +387,6 @@ "metadata": {}, "outputs": [], "source": [ - "# TEST\n", "assert len(price_by_flavor) == 4" ] }, @@ -314,7 +407,7 @@ } ], "source": [ - "# HIDDEN TEST\n", + "# HIDDEN\n", "np.isclose(price_by_flavor[\"chocolate\"], 3.33333333)" ] }, @@ -335,7 +428,7 @@ } ], "source": [ - "# HIDDEN TEST\n", + "# HIDDEN\n", "np.isclose(price_by_flavor[\"mint\"], 4.5)" ] }, @@ -356,7 +449,7 @@ } ], "source": [ - "# HIDDEN TEST\n", + "# HIDDEN\n", "np.isclose(price_by_flavor[\"strawberry\"], 3)" ] }, @@ -377,21 +470,45 @@ } ], "source": [ - "# HIDDEN TEST\n", + "# HIDDEN\n", "np.isclose(price_by_flavor[\"vanilla\"], 1.75)" ] }, { - "cell_type": "markdown", + "cell_type": "raw", "metadata": {}, "source": [ - "**Question 4:** Create a barplot of `price_by_flavor`.\n", - "\n", - "```\n", - "BEGIN QUESTION\n", + "# END TESTS" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END QUESTION" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN QUESTION\n", "name: q4\n", - "manual: true\n", - "```" + "manual: true" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Question 4:** Create a barplot of `price_by_flavor`." + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN SOLUTION" ] }, { @@ -417,16 +534,40 @@ ] }, { - "cell_type": "markdown", + "cell_type": "raw", "metadata": {}, "source": [ - "**Question 5:** What do you notice about the bar plot?\n", - "\n", - "```\n", - "BEGIN QUESTION\n", + "# END SOLUTION" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END QUESTION" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN QUESTION\n", "name: q5\n", - "manual: true\n", - "```" + "manual: true" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Question 5:** What do you notice about the bar plot?" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# BEGIN SOLUTION" ] }, { @@ -435,6 +576,20 @@ "source": [ "**SOLUTION:** mint is the highest...?" ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END SOLUTION" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "# END QUESTION" + ] } ], "metadata": { @@ -453,7 +608,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.7" }, "varInspector": { "cols": {