diff --git a/nbgrader/apps/__init__.py b/nbgrader/apps/__init__.py
index da8192e0..12b32d9c 100644
--- a/nbgrader/apps/__init__.py
+++ b/nbgrader/apps/__init__.py
@@ -18,6 +18,7 @@ from .dbapp import (
     DbAssignmentAddApp, DbAssignmentRemoveApp, DbAssignmentImportApp, DbAssignmentListApp)
 from .updateapp import UpdateApp
 from .zipcollectapp import ZipCollectApp
+from .generateconfigapp import GenerateConfigApp
 from .nbgraderapp import NbGraderApp
 from .api import NbGraderAPI
 
@@ -50,5 +51,6 @@ __all__ = [
     'DbAssignmentListApp',
     'UpdateApp',
     'ZipCollectApp',
+    'GenerateConfigApp'
     'NbGraderAPI'
 ]
diff --git a/nbgrader/apps/generateconfigapp.py b/nbgrader/apps/generateconfigapp.py
new file mode 100644
index 00000000..6c0ea220
--- /dev/null
+++ b/nbgrader/apps/generateconfigapp.py
@@ -0,0 +1,34 @@
+# coding: utf-8
+
+import os
+
+from traitlets import Unicode
+from traitlets.config.application import catch_config_error
+from .baseapp import NbGrader
+
+
+class GenerateConfigApp(NbGrader):
+
+    name = u'nbgrader-generate-config'
+    description = u'Generates a default nbgrader_config.py file'
+    examples = ""
+
+    filename = Unicode(
+        "nbgrader_config.py",
+        help="The name of the configuration file to generate."
+    ).tag(config=True)
+
+    @catch_config_error
+    def initialize(self, argv=None):
+        super(GenerateConfigApp, self).initialize(argv)
+
+    def start(self):
+        super(GenerateConfigApp, self).start()
+        s = self.generate_config_file()
+
+        if os.path.exists(self.filename):
+            self.fail("Config file '{}' already exists".format(self.filename))
+
+        with open(self.filename, 'w') as fh:
+            fh.write(s)
+        self.log.info("New config file saved to '{}'".format(self.filename))
diff --git a/nbgrader/apps/nbgraderapp.py b/nbgrader/apps/nbgraderapp.py
index cde01949..dbfc55ed 100755
--- a/nbgrader/apps/nbgraderapp.py
+++ b/nbgrader/apps/nbgraderapp.py
@@ -35,6 +35,7 @@ from . import (
     DbApp,
     UpdateApp,
     ZipCollectApp,
+    GenerateConfigApp
 )
 
 aliases = {}
@@ -45,10 +46,6 @@ aliases.update({
 flags = {}
 flags.update(nbgrader_flags)
 flags.update({
-    'generate-config': (
-        {'NbGraderApp' : {'generate_config': True}},
-        "Generate a config file."
-    )
 })
 
 
@@ -234,7 +231,15 @@ class NbGraderApp(NbGrader):
                 Update nbgrader cell metadata to the most recent version.
                 """
             ).strip()
-        )
+        ),
+        generate_config=(
+            GenerateConfigApp,
+            dedent(
+                """
+                Generates a default nbgrader_config.py file.
+                """
+            ).strip()
+        ),
     )
 
     @default("classes")
@@ -280,19 +285,6 @@ class NbGraderApp(NbGrader):
         super(NbGraderApp, self).initialize(argv)
 
     def start(self):
-        # if we're generating a config file, then do only that
-        if self.generate_config:
-            s = self.generate_config_file()
-            filename = "nbgrader_config.py"
-
-            if os.path.exists(filename):
-                self.fail("Config file '{}' already exists".format(filename))
-
-            with open(filename, 'w') as fh:
-                fh.write(s)
-            self.log.info("New config file saved to '{}'".format(filename))
-            raise NoStart()
-
         # check: is there a subapp given?
         if self.subapp is None:
             print("No command given (run with --help for options). List of subcommands:\n")
diff --git a/nbgrader/apps/quickstartapp.py b/nbgrader/apps/quickstartapp.py
index 05925445..77154df3 100644
--- a/nbgrader/apps/quickstartapp.py
+++ b/nbgrader/apps/quickstartapp.py
@@ -99,7 +99,7 @@ class QuickStartApp(NbGrader):
         self.log.info("Generating example config file...")
         currdir = os.getcwd()
         os.chdir(course_path)
-        subprocess.call([sys.executable, "-m", "nbgrader", "--generate-config"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        subprocess.call([sys.executable, "-m", "nbgrader", "generate_config"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
         os.chdir(currdir)
         with open(os.path.join(course_path, "nbgrader_config.py"), "r") as fh:
             config = fh.read()
diff --git a/nbgrader/docs/source/build_docs.py b/nbgrader/docs/source/build_docs.py
index 976fab0e..943f4bb8 100644
--- a/nbgrader/docs/source/build_docs.py
+++ b/nbgrader/docs/source/build_docs.py
@@ -46,6 +46,7 @@ def autogen_command_line(root):
         'UpdateApp',
         'ValidateApp',
         'ZipCollectApp',
+        'GenerateConfigApp'
     ]
 
     print('Generating command line documentation')
diff --git a/nbgrader/docs/source/command_line_tools/index.rst b/nbgrader/docs/source/command_line_tools/index.rst
index b7250061..b10ba74a 100644
--- a/nbgrader/docs/source/command_line_tools/index.rst
+++ b/nbgrader/docs/source/command_line_tools/index.rst
@@ -8,6 +8,7 @@ Basic commands
     :maxdepth: 1
 
     nbgrader
+    nbgrader-generate-config
 
 Instructor commands
 -------------------
diff --git a/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/problem1.ipynb b/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/problem1.ipynb
index c1cd1475..48e896bb 100644
--- a/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/problem1.ipynb
+++ b/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/problem1.ipynb
@@ -136,7 +136,7 @@
      "traceback": [
       "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
       "\u001b[0;31mAssertionError\u001b[0m                            Traceback (most recent call last)",
-      "\u001b[0;32m<ipython-input-4-c7326d393566>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;34m\"\"\"Check that squares returns the correct output for several inputs\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0msquares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msquares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msquares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m16\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m25\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m36\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m49\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m64\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m81\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m100\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msquares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m16\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m25\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m36\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m49\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m64\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m81\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m100\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m121\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-4-f3fef5b9ed4e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;34m\"\"\"Check that squares returns the correct output for several inputs\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0msquares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msquares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msquares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m16\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m25\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m36\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m49\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m64\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m81\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m100\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msquares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m16\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m25\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m36\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m49\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m64\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m81\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m100\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m121\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
       "\u001b[0;31mAssertionError\u001b[0m: "
      ]
     }
@@ -274,7 +274,7 @@
      "traceback": [
       "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
       "\u001b[0;31mAssertionError\u001b[0m                            Traceback (most recent call last)",
-      "\u001b[0;32m<ipython-input-8-3982d45be654>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;34m\"\"\"Check that sum_of_squares returns the correct answer for various inputs.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0msum_of_squares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msum_of_squares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msum_of_squares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m385\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msum_of_squares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m506\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m<ipython-input-8-1a00eaa7c988>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;34m\"\"\"Check that sum_of_squares returns the correct answer for various inputs.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0msum_of_squares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msum_of_squares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msum_of_squares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m385\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0msum_of_squares\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m506\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
       "\u001b[0;31mAssertionError\u001b[0m: "
      ]
     }
@@ -384,7 +384,7 @@
      "traceback": [
       "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
       "\u001b[0;31mNotImplementedError\u001b[0m                       Traceback (most recent call last)",
-      "\u001b[0;32m<ipython-input-10-a3eb14613b08>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# YOUR CODE HERE\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mNotImplementedError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;32m<ipython-input-10-15b94d1fa268>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# YOUR CODE HERE\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mNotImplementedError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
       "\u001b[0;31mNotImplementedError\u001b[0m: "
      ]
     }
diff --git a/nbgrader/docs/source/user_guide/creating_and_grading_assignments.ipynb b/nbgrader/docs/source/user_guide/creating_and_grading_assignments.ipynb
index 7c6a3d68..83164922 100644
--- a/nbgrader/docs/source/user_guide/creating_and_grading_assignments.ipynb
+++ b/nbgrader/docs/source/user_guide/creating_and_grading_assignments.ipynb
@@ -855,8 +855,8 @@
      "output_type": "stream",
      "text": [
       "[AutogradeApp | WARNING] No nbgrader_config.py file found (rerun with --debug to see where nbgrader is looking)\n",
-      "[AutogradeApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted/bitdiddle/ps1/jupyter.png -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/jupyter.png\n",
       "[AutogradeApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted/bitdiddle/ps1/timestamp.txt -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/timestamp.txt\n",
+      "[AutogradeApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted/bitdiddle/ps1/jupyter.png -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/jupyter.png\n",
       "[AutogradeApp | INFO] Creating/updating student with ID 'bitdiddle': {}\n",
       "[AutogradeApp | INFO] SubmittedAssignment<ps1 for bitdiddle> submitted at 2015-02-02 14:58:23.948203\n",
       "[AutogradeApp | INFO] Overwriting files with master versions from the source directory\n",
@@ -878,8 +878,8 @@
       "[AutogradeApp | INFO] Executing notebook with kernel: python\n",
       "[AutogradeApp | INFO] Writing 2356 bytes to /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/problem2.ipynb\n",
       "[AutogradeApp | INFO] Setting destination file permissions to 444\n",
-      "[AutogradeApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted/hacker/ps1/jupyter.png -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/hacker/ps1/jupyter.png\n",
       "[AutogradeApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted/hacker/ps1/timestamp.txt -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/hacker/ps1/timestamp.txt\n",
+      "[AutogradeApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted/hacker/ps1/jupyter.png -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/hacker/ps1/jupyter.png\n",
       "[AutogradeApp | INFO] Creating/updating student with ID 'hacker': {}\n",
       "[AutogradeApp | INFO] SubmittedAssignment<ps1 for hacker> submitted at 2015-02-01 09:28:58.749302\n",
       "[AutogradeApp | INFO] Overwriting files with master versions from the source directory\n",
@@ -1060,15 +1060,15 @@
      "output_type": "stream",
      "text": [
       "[FeedbackApp | WARNING] No nbgrader_config.py file found (rerun with --debug to see where nbgrader is looking)\n",
-      "[FeedbackApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/jupyter.png -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/jupyter.png\n",
       "[FeedbackApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/timestamp.txt -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/timestamp.txt\n",
+      "[FeedbackApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/jupyter.png -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/jupyter.png\n",
       "[FeedbackApp | INFO] Converting notebook /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/problem1.ipynb\n",
       "[FeedbackApp | INFO] Writing 275507 bytes to /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/problem1.html\n",
       "[FeedbackApp | INFO] Converting notebook /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/problem2.ipynb\n",
       "[FeedbackApp | INFO] Writing 254432 bytes to /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/problem2.html\n",
       "[FeedbackApp | INFO] Setting destination file permissions to 644\n",
-      "[FeedbackApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/hacker/ps1/jupyter.png -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/feedback/hacker/ps1/jupyter.png\n",
       "[FeedbackApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/hacker/ps1/timestamp.txt -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/feedback/hacker/ps1/timestamp.txt\n",
+      "[FeedbackApp | INFO] Copying /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/hacker/ps1/jupyter.png -> /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/feedback/hacker/ps1/jupyter.png\n",
       "[FeedbackApp | INFO] Converting notebook /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/hacker/ps1/problem1.ipynb\n",
       "[FeedbackApp | INFO] Writing 271810 bytes to /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/feedback/hacker/ps1/problem1.html\n",
       "[FeedbackApp | INFO] Converting notebook /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/autograded/hacker/ps1/problem2.ipynb\n",
diff --git a/nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/problem1.html b/nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/problem1.html
index d3a94acb..4bcbab02 100644
--- a/nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/problem1.html
+++ b/nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/problem1.html
@@ -12079,7 +12079,7 @@ span.nbgrader-label {
 <pre>
 <span class="ansi-red-fg">---------------------------------------------------------------------------</span>
 <span class="ansi-red-fg">AssertionError</span>                            Traceback (most recent call last)
-<span class="ansi-green-fg">&lt;ipython-input-4-c7326d393566&gt;</span> in <span class="ansi-cyan-fg">&lt;module&gt;</span><span class="ansi-blue-fg">()</span>
+<span class="ansi-green-fg">&lt;ipython-input-4-f3fef5b9ed4e&gt;</span> in <span class="ansi-cyan-fg">&lt;module&gt;</span><span class="ansi-blue-fg">()</span>
 <span class="ansi-green-intense-fg ansi-bold">      1</span> <span class="ansi-blue-fg">&#34;&#34;&#34;Check that squares returns the correct output for several inputs&#34;&#34;&#34;</span>
 <span class="ansi-green-fg">----&gt; 2</span><span class="ansi-red-fg"> </span><span class="ansi-green-fg">assert</span> squares<span class="ansi-blue-fg">(</span><span class="ansi-cyan-fg">1</span><span class="ansi-blue-fg">)</span> <span class="ansi-blue-fg">==</span> <span class="ansi-blue-fg">[</span><span class="ansi-cyan-fg">1</span><span class="ansi-blue-fg">]</span>
 <span class="ansi-green-intense-fg ansi-bold">      3</span> <span class="ansi-green-fg">assert</span> squares<span class="ansi-blue-fg">(</span><span class="ansi-cyan-fg">2</span><span class="ansi-blue-fg">)</span> <span class="ansi-blue-fg">==</span> <span class="ansi-blue-fg">[</span><span class="ansi-cyan-fg">1</span><span class="ansi-blue-fg">,</span> <span class="ansi-cyan-fg">4</span><span class="ansi-blue-fg">]</span>
@@ -12236,7 +12236,7 @@ span.nbgrader-label {
 <pre>
 <span class="ansi-red-fg">---------------------------------------------------------------------------</span>
 <span class="ansi-red-fg">AssertionError</span>                            Traceback (most recent call last)
-<span class="ansi-green-fg">&lt;ipython-input-8-3982d45be654&gt;</span> in <span class="ansi-cyan-fg">&lt;module&gt;</span><span class="ansi-blue-fg">()</span>
+<span class="ansi-green-fg">&lt;ipython-input-8-1a00eaa7c988&gt;</span> in <span class="ansi-cyan-fg">&lt;module&gt;</span><span class="ansi-blue-fg">()</span>
 <span class="ansi-green-intense-fg ansi-bold">      1</span> <span class="ansi-blue-fg">&#34;&#34;&#34;Check that sum_of_squares returns the correct answer for various inputs.&#34;&#34;&#34;</span>
 <span class="ansi-green-fg">----&gt; 2</span><span class="ansi-red-fg"> </span><span class="ansi-green-fg">assert</span> sum_of_squares<span class="ansi-blue-fg">(</span><span class="ansi-cyan-fg">1</span><span class="ansi-blue-fg">)</span> <span class="ansi-blue-fg">==</span> <span class="ansi-cyan-fg">1</span>
 <span class="ansi-green-intense-fg ansi-bold">      3</span> <span class="ansi-green-fg">assert</span> sum_of_squares<span class="ansi-blue-fg">(</span><span class="ansi-cyan-fg">2</span><span class="ansi-blue-fg">)</span> <span class="ansi-blue-fg">==</span> <span class="ansi-cyan-fg">5</span>
@@ -12354,7 +12354,7 @@ span.nbgrader-label {
 <pre>
 <span class="ansi-red-fg">---------------------------------------------------------------------------</span>
 <span class="ansi-red-fg">NotImplementedError</span>                       Traceback (most recent call last)
-<span class="ansi-green-fg">&lt;ipython-input-10-a3eb14613b08&gt;</span> in <span class="ansi-cyan-fg">&lt;module&gt;</span><span class="ansi-blue-fg">()</span>
+<span class="ansi-green-fg">&lt;ipython-input-10-15b94d1fa268&gt;</span> in <span class="ansi-cyan-fg">&lt;module&gt;</span><span class="ansi-blue-fg">()</span>
 <span class="ansi-green-intense-fg ansi-bold">      1</span> <span class="ansi-red-fg"># YOUR CODE HERE</span>
 <span class="ansi-green-fg">----&gt; 2</span><span class="ansi-red-fg"> </span><span class="ansi-green-fg">raise</span> NotImplementedError<span class="ansi-blue-fg">(</span><span class="ansi-blue-fg">)</span>
 
diff --git a/nbgrader/docs/source/user_guide/managing_assignment_files.ipynb b/nbgrader/docs/source/user_guide/managing_assignment_files.ipynb
index 7dd5743f..e762013d 100644
--- a/nbgrader/docs/source/user_guide/managing_assignment_files.ipynb
+++ b/nbgrader/docs/source/user_guide/managing_assignment_files.ipynb
@@ -415,9 +415,9 @@
      "output_type": "stream",
      "text": [
       "total 40\n",
-      "-rw-r--r--  1 jhamrick  wheel  5733 Oct 29 13:17 jupyter.png\n",
-      "-rw-r--r--  1 jhamrick  wheel  8126 Oct 29 13:17 problem1.ipynb\n",
-      "-rw-r--r--  1 jhamrick  wheel  2318 Oct 29 13:17 problem2.ipynb\n"
+      "-rw-r--r--  1 jhamrick  wheel  5733 Apr 22 15:29 jupyter.png\n",
+      "-rw-r--r--  1 jhamrick  wheel  8126 Apr 22 15:29 problem1.ipynb\n",
+      "-rw-r--r--  1 jhamrick  wheel  2318 Apr 22 15:29 problem2.ipynb\n"
      ]
     }
    ],
@@ -585,8 +585,8 @@
      "output_type": "stream",
      "text": [
       "[SubmitApp | INFO] Source: /private/tmp/student_home/ps1\n",
-      "[SubmitApp | INFO] Destination: /tmp/exchange/example_course/inbound/jhamrick+ps1+2017-10-29 13:17:40.891463 UTC\n",
-      "[SubmitApp | INFO] Submitted as: example_course ps1 2017-10-29 13:17:40.891463 UTC\n"
+      "[SubmitApp | INFO] Destination: /tmp/exchange/example_course/inbound/jhamrick+ps1+2018-04-22 14:29:40.397476 UTC\n",
+      "[SubmitApp | INFO] Submitted as: example_course ps1 2018-04-22 14:29:40.397476 UTC\n"
      ]
     }
    ],
@@ -614,9 +614,9 @@
      "output_type": "stream",
      "text": [
       "total 8\n",
-      "drwxr-xr-x  3 jhamrick  wheel  102 Oct 29 13:17 Library\n",
-      "-rw-r--r--  1 jhamrick  wheel   91 Oct 29 13:17 nbgrader_config.py\n",
-      "drwxr-xr-x  5 jhamrick  wheel  170 Oct 29 13:17 ps1\n"
+      "drwxr-xr-x  3 jhamrick  wheel   96 Apr 22 15:29 Library\n",
+      "-rw-r--r--  1 jhamrick  wheel   91 Apr 22 15:29 nbgrader_config.py\n",
+      "drwxr-xr-x  5 jhamrick  wheel  160 Apr 22 15:29 ps1\n"
      ]
     }
    ],
@@ -644,7 +644,7 @@
      "output_type": "stream",
      "text": [
       "[ListApp | INFO] Submitted assignments:\n",
-      "[ListApp | INFO] example_course jhamrick ps1 2017-10-29 13:17:40.891463 UTC\n"
+      "[ListApp | INFO] example_course jhamrick ps1 2018-04-22 14:29:40.397476 UTC\n"
      ]
     }
    ],
@@ -672,8 +672,8 @@
      "output_type": "stream",
      "text": [
       "[SubmitApp | INFO] Source: /private/tmp/student_home/ps1\n",
-      "[SubmitApp | INFO] Destination: /tmp/exchange/example_course/inbound/jhamrick+ps1+2017-10-29 13:17:43.778886 UTC\n",
-      "[SubmitApp | INFO] Submitted as: example_course ps1 2017-10-29 13:17:43.778886 UTC\n"
+      "[SubmitApp | INFO] Destination: /tmp/exchange/example_course/inbound/jhamrick+ps1+2018-04-22 14:29:43.070290 UTC\n",
+      "[SubmitApp | INFO] Submitted as: example_course ps1 2018-04-22 14:29:43.070290 UTC\n"
      ]
     }
    ],
@@ -701,8 +701,8 @@
      "output_type": "stream",
      "text": [
       "[ListApp | INFO] Submitted assignments:\n",
-      "[ListApp | INFO] example_course jhamrick ps1 2017-10-29 13:17:40.891463 UTC\n",
-      "[ListApp | INFO] example_course jhamrick ps1 2017-10-29 13:17:43.778886 UTC\n"
+      "[ListApp | INFO] example_course jhamrick ps1 2018-04-22 14:29:40.397476 UTC\n",
+      "[ListApp | INFO] example_course jhamrick ps1 2018-04-22 14:29:43.070290 UTC\n"
      ]
     }
    ],
@@ -737,7 +737,7 @@
      "output_type": "stream",
      "text": [
       "[SubmitApp | INFO] Source: /private/tmp/student_home/ps1\n",
-      "[SubmitApp | INFO] Destination: /tmp/exchange/example_course/inbound/jhamrick+ps1+2017-10-29 13:17:46.694803 UTC\n",
+      "[SubmitApp | INFO] Destination: /tmp/exchange/example_course/inbound/jhamrick+ps1+2018-04-22 14:29:46.167901 UTC\n",
       "[SubmitApp | WARNING] Possible missing notebooks and/or extra notebooks submitted for assignment ps1:\n",
       "    Expected:\n",
       "    \tproblem1.ipynb: MISSING\n",
@@ -745,7 +745,7 @@
       "    Submitted:\n",
       "    \tmyproblem1.ipynb: EXTRA\n",
       "    \tproblem2.ipynb: OK\n",
-      "[SubmitApp | INFO] Submitted as: example_course ps1 2017-10-29 13:17:46.694803 UTC\n"
+      "[SubmitApp | INFO] Submitted as: example_course ps1 2018-04-22 14:29:46.167901 UTC\n"
      ]
     }
    ],
@@ -805,7 +805,7 @@
      "output_type": "stream",
      "text": [
       "[SubmitApp | INFO] Source: /private/tmp/student_home/ps1\n",
-      "[SubmitApp | INFO] Destination: /tmp/exchange/example_course/inbound/jhamrick+ps1+2017-10-29 13:17:48.185532 UTC\n",
+      "[SubmitApp | INFO] Destination: /tmp/exchange/example_course/inbound/jhamrick+ps1+2018-04-22 14:29:47.497419 UTC\n",
       "[SubmitApp | CRITICAL] Assignment ps1 not submitted. There are missing notebooks for the submission:\n",
       "    Expected:\n",
       "    \tproblem1.ipynb: MISSING\n",
@@ -931,9 +931,9 @@
      "output_type": "stream",
      "text": [
       "[ListApp | INFO] Submitted assignments:\n",
-      "[ListApp | INFO] example_course jhamrick ps1 2017-10-29 13:17:40.891463 UTC\n",
-      "[ListApp | INFO] example_course jhamrick ps1 2017-10-29 13:17:43.778886 UTC\n",
-      "[ListApp | INFO] example_course jhamrick ps1 2017-10-29 13:17:46.694803 UTC\n"
+      "[ListApp | INFO] example_course jhamrick ps1 2018-04-22 14:29:40.397476 UTC\n",
+      "[ListApp | INFO] example_course jhamrick ps1 2018-04-22 14:29:43.070290 UTC\n",
+      "[ListApp | INFO] example_course jhamrick ps1 2018-04-22 14:29:46.167901 UTC\n"
      ]
     }
    ],
@@ -987,9 +987,9 @@
      "output_type": "stream",
      "text": [
       "total 0\n",
-      "drwxr-xr-x  3 jhamrick  staff  102 May 31 19:10 bitdiddle\n",
-      "drwxr-xr-x  3 jhamrick  staff  102 May 31 19:10 hacker\n",
-      "drwxr-xr-x  3 jhamrick  staff  102 Oct 29 13:17 jhamrick\n"
+      "drwxr-xr-x  3 jhamrick  staff  96 May 31  2017 bitdiddle\n",
+      "drwxr-xr-x  3 jhamrick  staff  96 May 31  2017 hacker\n",
+      "drwxr-xr-x  3 jhamrick  staff  96 Apr 22 15:29 jhamrick\n"
      ]
     }
    ],
diff --git a/nbgrader/docs/source/user_guide/managing_assignment_files_manually.ipynb b/nbgrader/docs/source/user_guide/managing_assignment_files_manually.ipynb
index 12db2131..d3828217 100644
--- a/nbgrader/docs/source/user_guide/managing_assignment_files_manually.ipynb
+++ b/nbgrader/docs/source/user_guide/managing_assignment_files_manually.ipynb
@@ -180,8 +180,8 @@
      "output_type": "stream",
      "text": [
       "total 64\n",
-      "-rw-r--r--  1 jhamrick  staff  18465 Oct 29 13:15 notebooks.zip\n",
-      "-rw-r--r--  1 jhamrick  staff   8870 Oct 29 13:16 ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n"
+      "-rw-r--r--  1 jhamrick  staff  18465 Oct 29 20:04 notebooks.zip\n",
+      "-rw-r--r--  1 jhamrick  staff   8870 Apr 22 15:28 ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n"
      ]
     }
    ],
@@ -259,8 +259,8 @@
      "output_type": "stream",
      "text": [
       "total 64\n",
-      "-rw-r--r--  1 jhamrick  staff  18465 Oct 29 13:15 notebooks.zip\n",
-      "-rw-r--r--  1 jhamrick  staff   8870 Oct 29 13:16 ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n"
+      "-rw-r--r--  1 jhamrick  staff  18465 Oct 29 20:04 notebooks.zip\n",
+      "-rw-r--r--  1 jhamrick  staff   8870 Apr 22 15:28 ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n"
      ]
     }
    ],
@@ -355,10 +355,10 @@
       "[ZipCollectApp | INFO] Using file extractor: ExtractorPlugin\n",
       "[ZipCollectApp | INFO] Using file collector: FileNameCollectorPlugin\n",
       "[ZipCollectApp | WARNING] Directory not found. Creating: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted\n",
-      "[ZipCollectApp | INFO] Extracting from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/archive/notebooks.zip\n",
-      "[ZipCollectApp | INFO]   Extracting to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks\n",
       "[ZipCollectApp | INFO] Copying from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/archive/ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n",
       "[ZipCollectApp | INFO]   Copying to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n",
+      "[ZipCollectApp | INFO] Extracting from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/archive/notebooks.zip\n",
+      "[ZipCollectApp | INFO]   Extracting to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks\n",
       "[ZipCollectApp | INFO] Start collecting files...\n",
       "[ZipCollectApp | INFO] Parsing file: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks/ps1_bitdiddle_attempt_2016-01-30-15-30-10_jupyter.png\n",
       "[ZipCollectApp | WARNING] Skipped submission with no match information provided: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks/ps1_bitdiddle_attempt_2016-01-30-15-30-10_jupyter.png\n",
@@ -410,15 +410,15 @@
      "output_type": "stream",
      "text": [
       "total 24\n",
-      "drwxr-xr-x  8 jhamrick  staff   272 Oct 29 13:17 notebooks\n",
-      "-rw-r--r--  1 jhamrick  staff  8870 Oct 29 13:17 ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n",
+      "drwxr-xr-x  8 jhamrick  staff   256 Apr 22 15:29 notebooks\n",
+      "-rw-r--r--  1 jhamrick  staff  8870 Apr 22 15:29 ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n",
       "total 88\n",
-      "-rw-rw-r--  1 jhamrick  staff  5733 Oct 29 13:17 ps1_bitdiddle_attempt_2016-01-30-15-30-10_jupyter.png\n",
-      "-rw-rw-r--  1 jhamrick  staff  7954 Oct 29 13:17 ps1_bitdiddle_attempt_2016-01-30-15-30-10_problem1.ipynb\n",
-      "-rw-rw-r--  1 jhamrick  staff  2288 Oct 29 13:17 ps1_bitdiddle_attempt_2016-01-30-15-30-10_problem2.ipynb\n",
-      "-rw-rw-r--  1 jhamrick  staff  5733 Oct 29 13:17 ps1_hacker_attempt_2016-01-30-16-30-10_jupyter.png\n",
-      "-rw-rw-r--  1 jhamrick  staff  9072 Oct 29 13:17 ps1_hacker_attempt_2016-01-30-16-30-10_myproblem1.ipynb\n",
-      "-rw-rw-r--  1 jhamrick  staff  2418 Oct 29 13:17 ps1_hacker_attempt_2016-01-30-16-30-10_problem2.ipynb\n"
+      "-rw-rw-r--  1 jhamrick  staff  5733 Apr 22 15:29 ps1_bitdiddle_attempt_2016-01-30-15-30-10_jupyter.png\n",
+      "-rw-rw-r--  1 jhamrick  staff  7954 Apr 22 15:29 ps1_bitdiddle_attempt_2016-01-30-15-30-10_problem1.ipynb\n",
+      "-rw-rw-r--  1 jhamrick  staff  2288 Apr 22 15:29 ps1_bitdiddle_attempt_2016-01-30-15-30-10_problem2.ipynb\n",
+      "-rw-rw-r--  1 jhamrick  staff  5733 Apr 22 15:29 ps1_hacker_attempt_2016-01-30-16-30-10_jupyter.png\n",
+      "-rw-rw-r--  1 jhamrick  staff  9072 Apr 22 15:29 ps1_hacker_attempt_2016-01-30-16-30-10_myproblem1.ipynb\n",
+      "-rw-rw-r--  1 jhamrick  staff  2418 Apr 22 15:29 ps1_hacker_attempt_2016-01-30-16-30-10_problem2.ipynb\n"
      ]
     }
    ],
@@ -448,8 +448,8 @@
      "output_type": "stream",
      "text": [
       "total 0\n",
-      "drwxr-xr-x  3 jhamrick  staff  102 Oct 29 13:17 bitdiddle\n",
-      "drwxr-xr-x  3 jhamrick  staff  102 Oct 29 13:17 hacker\n"
+      "drwxr-xr-x  3 jhamrick  staff  96 Apr 22 15:29 bitdiddle\n",
+      "drwxr-xr-x  3 jhamrick  staff  96 Apr 22 15:29 hacker\n"
      ]
     }
    ],
@@ -469,9 +469,9 @@
      "output_type": "stream",
      "text": [
       "total 40\n",
-      "-rw-r--r--  1 jhamrick  staff  8870 Oct 29 13:17 problem1.ipynb\n",
-      "-rw-rw-r--  1 jhamrick  staff  2418 Oct 29 13:17 problem2.ipynb\n",
-      "-rw-r--r--  1 jhamrick  staff    19 Oct 29 13:17 timestamp.txt\n"
+      "-rw-r--r--  1 jhamrick  staff  8870 Apr 22 15:29 problem1.ipynb\n",
+      "-rw-rw-r--  1 jhamrick  staff  2418 Apr 22 15:29 problem2.ipynb\n",
+      "-rw-r--r--  1 jhamrick  staff    19 Apr 22 15:29 timestamp.txt\n"
      ]
     }
    ],
@@ -567,10 +567,10 @@
       "[ZipCollectApp | INFO] Using file extractor: ExtractorPlugin\n",
       "[ZipCollectApp | INFO] Using file collector: CustomPlugin\n",
       "[ZipCollectApp | WARNING] Clearing existing files in /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted\n",
-      "[ZipCollectApp | INFO] Extracting from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/archive/notebooks.zip\n",
-      "[ZipCollectApp | INFO]   Extracting to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks\n",
       "[ZipCollectApp | INFO] Copying from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/archive/ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n",
       "[ZipCollectApp | INFO]   Copying to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n",
+      "[ZipCollectApp | INFO] Extracting from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/archive/notebooks.zip\n",
+      "[ZipCollectApp | INFO]   Extracting to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks\n",
       "[ZipCollectApp | INFO] Start collecting files...\n",
       "[ZipCollectApp | INFO] Parsing file: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks/ps1_bitdiddle_attempt_2016-01-30-15-30-10_jupyter.png\n",
       "[ZipCollectApp | WARNING] Skipped submission with no match information provided: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks/ps1_bitdiddle_attempt_2016-01-30-15-30-10_jupyter.png\n",
@@ -584,18 +584,18 @@
       "[ZipCollectApp | INFO] Parsing file: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n",
       "[ZipCollectApp | WARNING] 4 files collected, 3 files skipped\n",
       "[ZipCollectApp | INFO] Start transfering files...\n",
-      "[ZipCollectApp | WARNING] Clearing existing files in /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/bitdiddle/ps1\n",
-      "[ZipCollectApp | INFO] Copying from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks/ps1_bitdiddle_attempt_2016-01-30-15-30-10_problem1.ipynb\n",
-      "[ZipCollectApp | INFO]   Copying to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/bitdiddle/ps1/problem1.ipynb\n",
-      "[ZipCollectApp | INFO] Copying from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks/ps1_bitdiddle_attempt_2016-01-30-15-30-10_problem2.ipynb\n",
-      "[ZipCollectApp | INFO]   Copying to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/bitdiddle/ps1/problem2.ipynb\n",
-      "[ZipCollectApp | INFO] Creating timestamp: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/bitdiddle/ps1/timestamp.txt\n",
       "[ZipCollectApp | WARNING] Clearing existing files in /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/hacker/ps1\n",
       "[ZipCollectApp | INFO] Copying from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks/ps1_hacker_attempt_2016-01-30-16-30-10_problem2.ipynb\n",
       "[ZipCollectApp | INFO]   Copying to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/hacker/ps1/problem2.ipynb\n",
       "[ZipCollectApp | INFO] Copying from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/ps1_hacker_attempt_2016-01-30-20-30-10_problem1.ipynb\n",
       "[ZipCollectApp | INFO]   Copying to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/hacker/ps1/problem1.ipynb\n",
-      "[ZipCollectApp | INFO] Creating timestamp: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/hacker/ps1/timestamp.txt\n"
+      "[ZipCollectApp | INFO] Creating timestamp: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/hacker/ps1/timestamp.txt\n",
+      "[ZipCollectApp | WARNING] Clearing existing files in /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/bitdiddle/ps1\n",
+      "[ZipCollectApp | INFO] Copying from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks/ps1_bitdiddle_attempt_2016-01-30-15-30-10_problem1.ipynb\n",
+      "[ZipCollectApp | INFO]   Copying to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/bitdiddle/ps1/problem1.ipynb\n",
+      "[ZipCollectApp | INFO] Copying from: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/downloaded/ps1/extracted/notebooks/ps1_bitdiddle_attempt_2016-01-30-15-30-10_problem2.ipynb\n",
+      "[ZipCollectApp | INFO]   Copying to: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/bitdiddle/ps1/problem2.ipynb\n",
+      "[ZipCollectApp | INFO] Creating timestamp: /Users/jhamrick/project/tools/nbgrader/nbgrader/docs/source/user_guide/submitted_zip/bitdiddle/ps1/timestamp.txt\n"
      ]
     }
    ],
diff --git a/nbgrader/docs/source/user_guide/managing_the_database.ipynb b/nbgrader/docs/source/user_guide/managing_the_database.ipynb
index e3f216fb..94b48f3f 100644
--- a/nbgrader/docs/source/user_guide/managing_the_database.ipynb
+++ b/nbgrader/docs/source/user_guide/managing_the_database.ipynb
@@ -246,7 +246,7 @@
      "output_type": "stream",
      "text": [
       "[DbStudentAddApp | INFO] Creating/updating student with ID 'bitdiddle': {'last_name': 'Bitdiddle', 'first_name': 'Ben', 'email': None}\n",
-      "[DbStudentAddApp | INFO] Creating/updating student with ID 'hacker': {'last_name': 'Hacker', 'first_name': 'Alyssa', 'email': None}\n"
+      "[DbStudentAddApp | INFO] Creating/updating student with ID 'hacker': {'first_name': 'Alyssa', 'last_name': 'Hacker', 'email': None}\n"
      ]
     }
    ],
@@ -322,8 +322,8 @@
      "output_type": "stream",
      "text": [
       "[DbStudentImportApp | INFO] Importing from: 'students.csv'\n",
-      "[DbStudentImportApp | INFO] Creating/updating Student with id 'bitdiddle': {'email': None, 'first_name': 'Ben', 'last_name': 'Bitdiddle'}\n",
-      "[DbStudentImportApp | INFO] Creating/updating Student with id 'hacker': {'email': None, 'first_name': 'Alyssa', 'last_name': 'Hacker'}\n"
+      "[DbStudentImportApp | INFO] Creating/updating Student with id 'bitdiddle': {'first_name': 'Ben', 'email': None, 'last_name': 'Bitdiddle'}\n",
+      "[DbStudentImportApp | INFO] Creating/updating Student with id 'hacker': {'first_name': 'Alyssa', 'email': None, 'last_name': 'Hacker'}\n"
      ]
     }
    ],

Nbgrader.generate_config=False still generates a config file
Running:
`
nbgrader quickstart <course_id> --Nbgrader.config_file=/home/course/.jupyter/nbgrader_config --Nbgrader.generate_config=False
`
still generates a config file. Even though I say =False to generating it. And I give the path to the real config I have.

The docs are also misleading because they say generating a config is False by default:
[see docs](https://nbgrader.readthedocs.io/en/latest/command_line_tools/nbgrader-quickstart.html?highlight=quickstart)
```
--NbGrader.generate_config=<Bool>
    Default: False
    Generate default config file.
```


#### My versions
Ubuntu 16.04
jupyterhub version 0.8.1
notebook version 5.4.0
jupyter version 4.4.0
nbgrader version 0.6.0.dev (Also referred to as Formgrader)
canvasapi 0.8.2

diff --git a/nbgrader/tests/apps/test_nbgrader.py b/nbgrader/tests/apps/test_nbgrader.py
index 6d23fe5f..0666c521 100644
--- a/nbgrader/tests/apps/test_nbgrader.py
+++ b/nbgrader/tests/apps/test_nbgrader.py
@@ -15,19 +15,6 @@ class TestNbGrader(BaseTestApp):
         """Is the help displayed when no subapp is given?"""
         run_nbgrader([], retcode=0)
 
-    def test_generate_config(self):
-        """Is the config file properly generated?"""
-
-        # it already exists, because we create it in conftest.py
-        os.remove("nbgrader_config.py")
-
-        # try recreating it
-        run_nbgrader(["--generate-config"])
-        assert os.path.isfile("nbgrader_config.py")
-
-        # does it fail if it already exists?
-        run_nbgrader(["--generate-config"], retcode=1)
-
     def test_check_version(self, capfd):
         """Is the version the same regardless of how we run nbgrader?"""
         out1 = '\n'.join(
diff --git a/nbgrader/tests/apps/test_nbgrader_generate_config.py b/nbgrader/tests/apps/test_nbgrader_generate_config.py
new file mode 100644
index 00000000..7b95b401
--- /dev/null
+++ b/nbgrader/tests/apps/test_nbgrader_generate_config.py
@@ -0,0 +1,24 @@
+import os
+
+from .. import run_nbgrader
+from .base import BaseTestApp
+
+
+class TestNbGraderGenerateConfig(BaseTestApp):
+
+    def test_help(self):
+        """Does the help display without error?"""
+        run_nbgrader(["generate_config", "--help-all"])
+
+    def test_generate_config(self):
+        """Is the config file properly generated?"""
+
+        # it already exists, because we create it in conftest.py
+        os.remove("nbgrader_config.py")
+
+        # try recreating it
+        run_nbgrader(["generate_config"])
+        assert os.path.isfile("nbgrader_config.py")
+
+        # does it fail if it already exists?
+        run_nbgrader(["generate_config"], retcode=1)

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-rerunfailures coverage selenium invoke sphinx codecov cov-core pytest
apt-get update apt-get install -y gcc
3.6
dev-requirements.txt dev-requirements-windows.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.13
alembic==1.7.7
anyio==3.6.2
argon2-cffi==21.3.0
argon2-cffi-bindings==21.2.0
async-generator==1.10
attrs==22.2.0
Babel==2.11.0
backcall==0.2.0
bleach==4.1.0
certifi==2021.5.30
cffi==1.15.1
charset-normalizer==2.0.12
codecov==2.1.13
comm==0.1.4
contextvars==2.4
cov-core==1.15.0
coverage==6.2
dataclasses==0.8
decorator==5.1.1
defusedxml==0.7.1
docutils==0.18.1
entrypoints==0.4
greenlet==2.0.2
idna==3.10
imagesize==1.4.1
immutables==0.19
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
invoke==2.2.0
ipykernel==5.5.6
ipython==7.16.3
ipython-genutils==0.2.0
ipywidgets==7.8.5
jedi==0.17.2
Jinja2==3.0.3
json5==0.9.16
jsonschema==3.2.0
jupyter==1.1.1
jupyter-client==7.1.2
jupyter-console==6.4.3
jupyter-core==4.9.2
jupyter-server==1.13.1
jupyterlab==3.2.9
jupyterlab-pygments==0.1.2
jupyterlab-server==2.10.3
jupyterlab_widgets==1.1.11
Mako==1.1.6
MarkupSafe==2.0.1
mistune==0.8.4
nbclassic==0.3.5
nbclient==0.5.9
nbconvert==6.0.7
nbformat==5.1.3
-e git+https://github.com/jupyter/nbgrader.git@919c56a9782647a97bd03a0c9d6d0ac5633db0a3#egg=nbgrader
nbval==0.10.0
nest-asyncio==1.6.0
notebook==6.4.10
packaging==21.3
pandocfilters==1.5.1
parso==0.7.1
pexpect==4.9.0
pickleshare==0.7.5
pluggy==1.0.0
prometheus-client==0.17.1
prompt-toolkit==3.0.36
ptyprocess==0.7.0
py==1.11.0
pycparser==2.21
pyenchant==3.2.2
Pygments==2.14.0
pyparsing==3.1.4
pyrsistent==0.18.0
pytest==7.0.1
pytest-cov==4.0.0
pytest-rerunfailures==10.3
python-dateutil==2.9.0.post0
pytz==2025.2
pyzmq==25.1.2
requests==2.27.1
selenium==3.141.0
Send2Trash==1.8.3
six==1.17.0
sniffio==1.2.0
snowballstemmer==2.2.0
Sphinx==5.3.0
sphinx-rtd-theme==2.0.0
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
sphinxcontrib-spelling==7.7.0
SQLAlchemy==1.4.54
terminado==0.12.1
testpath==0.6.0
tomli==1.2.3
tornado==6.1
traitlets==4.3.3
typing_extensions==4.1.1
urllib3==1.26.20
wcwidth==0.2.13
webencodings==0.5.1
websocket-client==1.3.1
widgetsnbextension==3.6.10
zipp==3.6.0

name: nbgrader
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.13
      - alembic==1.7.7
      - anyio==3.6.2
      - argon2-cffi==21.3.0
      - argon2-cffi-bindings==21.2.0
      - async-generator==1.10
      - attrs==22.2.0
      - babel==2.11.0
      - backcall==0.2.0
      - bleach==4.1.0
      - cffi==1.15.1
      - charset-normalizer==2.0.12
      - codecov==2.1.13
      - comm==0.1.4
      - contextvars==2.4
      - cov-core==1.15.0
      - coverage==6.2
      - dataclasses==0.8
      - decorator==5.1.1
      - defusedxml==0.7.1
      - docutils==0.18.1
      - entrypoints==0.4
      - greenlet==2.0.2
      - idna==3.10
      - imagesize==1.4.1
      - immutables==0.19
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - invoke==2.2.0
      - ipykernel==5.5.6
      - ipython==7.16.3
      - ipython-genutils==0.2.0
      - ipywidgets==7.8.5
      - jedi==0.17.2
      - jinja2==3.0.3
      - json5==0.9.16
      - jsonschema==3.2.0
      - jupyter==1.1.1
      - jupyter-client==7.1.2
      - jupyter-console==6.4.3
      - jupyter-core==4.9.2
      - jupyter-server==1.13.1
      - jupyterlab==3.2.9
      - jupyterlab-pygments==0.1.2
      - jupyterlab-server==2.10.3
      - jupyterlab-widgets==1.1.11
      - mako==1.1.6
      - markupsafe==2.0.1
      - mistune==0.8.4
      - nbclassic==0.3.5
      - nbclient==0.5.9
      - nbconvert==6.0.7
      - nbformat==5.1.3
      - nbval==0.10.0
      - nest-asyncio==1.6.0
      - notebook==6.4.10
      - packaging==21.3
      - pandocfilters==1.5.1
      - parso==0.7.1
      - pexpect==4.9.0
      - pickleshare==0.7.5
      - pluggy==1.0.0
      - prometheus-client==0.17.1
      - prompt-toolkit==3.0.36
      - ptyprocess==0.7.0
      - py==1.11.0
      - pycparser==2.21
      - pyenchant==3.2.2
      - pygments==2.14.0
      - pyparsing==3.1.4
      - pyrsistent==0.18.0
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - pytest-rerunfailures==10.3
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyzmq==25.1.2
      - requests==2.27.1
      - selenium==3.141.0
      - send2trash==1.8.3
      - six==1.17.0
      - sniffio==1.2.0
      - snowballstemmer==2.2.0
      - sphinx==5.3.0
      - sphinx-rtd-theme==2.0.0
      - sphinxcontrib-applehelp==1.0.2
      - sphinxcontrib-devhelp==1.0.2
      - sphinxcontrib-htmlhelp==2.0.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==1.0.3
      - sphinxcontrib-serializinghtml==1.1.5
      - sphinxcontrib-spelling==7.7.0
      - sqlalchemy==1.4.54
      - terminado==0.12.1
      - testpath==0.6.0
      - tomli==1.2.3
      - tornado==6.1
      - traitlets==4.3.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - wcwidth==0.2.13
      - webencodings==0.5.1
      - websocket-client==1.3.1
      - widgetsnbextension==3.6.10
      - zipp==3.6.0
prefix: /opt/conda/envs/nbgrader

nbgrader/tests/apps/test_nbgrader_generate_config.py::TestNbGraderGenerateConfig::test_generate_config
nbgrader/tests/apps/test_nbgrader.py::TestNbGrader::test_help nbgrader/tests/apps/test_nbgrader.py::TestNbGrader::test_no_subapp nbgrader/tests/apps/test_nbgrader.py::TestNbGrader::test_check_version nbgrader/tests/apps/test_nbgrader_generate_config.py::TestNbGraderGenerateConfig::test_help
nbgrader/docs/source/command_line_tools/index.rst nbgrader/apps/quickstartapp.py nbgrader/docs/source/user_guide/managing_the_database.ipynb nbgrader/apps/generateconfigapp.py nbgrader/docs/source/build_docs.py nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/problem1.ipynb nbgrader/docs/source/user_guide/creating_and_grading_assignments.ipynb nbgrader/apps/__init__.py nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/problem1.html nbgrader/docs/source/user_guide/managing_assignment_files_manually.ipynb nbgrader/apps/nbgraderapp.py nbgrader/docs/source/user_guide/managing_assignment_files.ipynb
nbgrader/docs/source/command_line_tools/index.rst nbgrader/apps/quickstartapp.py nbgrader/docs/source/user_guide/managing_the_database.ipynb nbgrader/apps/generateconfigapp.py nbgrader/docs/source/build_docs.py nbgrader/docs/source/user_guide/autograded/bitdiddle/ps1/problem1.ipynb nbgrader/docs/source/user_guide/creating_and_grading_assignments.ipynb nbgrader/apps/__init__.py nbgrader/docs/source/user_guide/feedback/bitdiddle/ps1/problem1.html nbgrader/docs/source/user_guide/managing_assignment_files_manually.ipynb nbgrader/apps/nbgraderapp.py nbgrader/docs/source/user_guide/managing_assignment_files.ipynb