Repository: jupyter/nbgrader

Issue:
UI allows negative points 
The UI should probably only allow points within [0-\infty] for graded cells. It currently allows negative points.

![image](https://user-images.githubusercontent.com/393899/28242040-fcc939a6-6966-11e7-9b85-9d672051646a.png)


Discussion:

Patch:
diff --git a/nbgrader/docs/source/contributor_guide/metadata.rst b/nbgrader/docs/source/contributor_guide/metadata.rst
index d74f054d..4ede34a1 100644
--- a/nbgrader/docs/source/contributor_guide/metadata.rst
+++ b/nbgrader/docs/source/contributor_guide/metadata.rst
@@ -73,7 +73,8 @@ The metadata may contain the following keys:
     Added by the "Create Assignment" extension.
 
     This is the number of points that a cell is worth. It should only be
-    set if ``grade`` is also set to true.
+    set if ``grade`` is also set to true. The number of points must be greater
+    than or equal to zero.
 
 .. data:: checksum
 
diff --git a/nbgrader/nbextensions/create_assignment/main.js b/nbgrader/nbextensions/create_assignment/main.js
index 696908a4..ff4f8b3d 100644
--- a/nbgrader/nbextensions/create_assignment/main.js
+++ b/nbgrader/nbextensions/create_assignment/main.js
@@ -224,7 +224,9 @@ define([
         if (cell.metadata.nbgrader === undefined) {
             cell.metadata.nbgrader = {};
         }
-        cell.metadata.nbgrader.points = to_float(val);
+        var points = to_float(val);
+        if (points < 0) points = 0;
+        cell.metadata.nbgrader.points = points;
     };
 
     var get_grade_id = function (cell) {
diff --git a/nbgrader/nbgraderformat/v1.py b/nbgrader/nbgraderformat/v1.py
index 85afab34..5358d8d6 100644
--- a/nbgrader/nbgraderformat/v1.py
+++ b/nbgrader/nbgraderformat/v1.py
@@ -32,7 +32,11 @@ class ValidatorV1(BaseValidator):
             if meta['points'] == '':
                 meta['points'] = 0.0
             else:
-                meta['points'] = float(meta['points'])
+                points = float(meta['points'])
+                if points < 0:
+                    meta['points'] = 0.0
+                else:
+                    meta['points'] = float(meta['points'])
         else:
             meta['points'] = 0.0
 


Test patch:
diff --git a/nbgrader/tests/nbextensions/test_create_assignment.py b/nbgrader/tests/nbextensions/test_create_assignment.py
index da9bbc34..e972b4da 100644
--- a/nbgrader/tests/nbextensions/test_create_assignment.py
+++ b/nbgrader/tests/nbextensions/test_create_assignment.py
@@ -571,3 +571,24 @@ def test_cell_ids(browser, port):
     _save(browser)
     _wait_for_modal(browser)
     _dismiss_modal(browser)
+
+
+@pytest.mark.nbextensions
+def test_negative_points(browser, port):
+    _load_notebook(browser, port)
+    _activate_toolbar(browser)
+
+    # make sure the total points is zero
+    assert _get_total_points(browser) == 0
+
+    # make it autograder tests and set the points to two
+    _select_tests(browser)
+    _set_points(browser, points=2)
+    _set_id(browser)
+    assert _get_total_points(browser) == 2
+    assert 2 == _get_metadata(browser)['points']
+
+    # set the points to negative one
+    _set_points(browser, points=-1)
+    assert _get_total_points(browser) == 0
+    assert 0 == _get_metadata(browser)['points']
diff --git a/nbgrader/tests/nbgraderformat/test_v1.py b/nbgrader/tests/nbgraderformat/test_v1.py
index 1245aa5e..b85e4963 100644
--- a/nbgrader/tests/nbgraderformat/test_v1.py
+++ b/nbgrader/tests/nbgraderformat/test_v1.py
@@ -52,6 +52,10 @@ def test_set_points():
     ValidatorV1().upgrade_cell_metadata(cell)
     assert cell.metadata.nbgrader["points"] == 0.0
 
+    cell = create_grade_cell("", "code", "foo", -1, 0)
+    ValidatorV1().upgrade_cell_metadata(cell)
+    assert cell.metadata.nbgrader["points"] == 0.0
+
 
 def test_extra_keys():
     cell = create_grade_cell("", "code", "foo", "", 0)
@@ -65,4 +69,3 @@ def test_schema_version():
     del cell.metadata.nbgrader["schema_version"]
     ValidatorV1().upgrade_cell_metadata(cell)
     assert cell.metadata.nbgrader["schema_version"] == 1
-