dsassign 0.0.8
Jupyter notebook assignment formatting and distribution

# ds-assign: Jupyter Notebook Assignments
Format and tools for authoring and distributing Jupyter notebook assignments

Requires: **Python 3** (even if it's installed, check that it's your working version `python --version`)

## Background
This is a data 100 fork of dsassign (<https://github.com/DS-100/ds-assign>). 
Big change so far: 
Set student response cell types from "markdown" to "raw." Seems to fix a lot of latex problems.


## Getting started
Course instructors author assignments as Jupyter notebooks by creating a
notebook that contains setup code, questions, solutions, and tests to validate
those solutions. This project prepares an assignment to be distributed to
students and later scored automatically.

The [notebook format](docs/notebook-format.md) is not specific to a programming
language or autograding framework, but was designed to be used with
[okpy](https://github.com/okpy/ok), which is Python based. Contributions to
support other testing frameworks, such as [nbgrader[](), and other programming
languages are welcome.

An example notebook appears in `tests/example.ipynb`, which uses the [notebook
format](docs/notebook-format.md). To convert it, run:

```python
dsassign tests/example.ipynb tests/output some/course
```


* `tests/example.ipynb`: an example notebook path that you'll need to replace with the _path to the master solution notebook_, which was augmented with the metadata and commands from the [notebook format](docs/notebook-format.md).
* `tests/output`: _the path to where the output will be stored_ 
  * the output contains two directories `autograder` and `student`
  * the `autograder` directory contains the full set of tests and a solution notebook (a solution notebook is different from the master notebook, because it is not formatted accordidng to the [notebook format](docs/notebook-format.md) but instead looks like the student notebook with solutions)
  * the `student` directory contains an automatically created redacted version. 
  * **Note**: currently, the output directories will **not** contain the data files, e.g., csv or json files, that you used when creating the master notebook: make sure you add them to the `student` directory before releasing it to students
* `some/course` is the endpoint/path of the assignment that's listed on okpy (typically starts with your university abbreviation and has a course name in it, ending with the assignment name).


Before you run the `dsassign` command, make sure that you **run the entire notebook** top to bottom (`Cell -> Run All`) to make sure that every cell has the correct output -- the output of the cells will be turned into the appropriate tests stored in the provided output directory (second argument of the `dsassign` command). If you change the tests, you need to re-generate the files by re-running the notebook and the `dsassign` command. **Note**: `dsassign` will issue an error and quit if the output directory already exists.




You can then generate a PDF from the result:

```python
dsassign-pdf tests/output/autograder/example.ipynb tests/output/autograder/example.pdf
```


## Caution

#### Test outside of a question

```
File "/opt/conda/lib/python3.6/site-packages/dsassign/to_ok.py", line 141, in gen_ok_cells
    assert not is_test_cell(cell), 'Test outside of a question: ' + str(cell)
AssertionError: Test outside of a question:
```

If you get this error, this means that you have _more than one cell_ between the markdown cell that declared the question (i.e., the one that contains `#BEGIN QUESTION`) and the cell that contains the `# TEST`. 


**SOLUTION**: remove the extra code/markdown cell(s) either between the solution cell and the markdown cell with the `#BEGIN QUESTION` or between the solution cell and the `# TEST` cell.

#### Test cell with a blank on the last line

If your test contains a blank/newline after the test, dsassign seems to automatically add a semicolon at the end of the test, thus, supressing the output of the command.

Example:

```
# TEST
movies.head(1)['plots'][0]=='Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.'

```

Turns into the following failed test in the students' notebook:

```
>>> movies.head(1)['plots'][0]=='Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.';
>>> 

# Error: expected
#     True
# but got

```

**SOLUTION**: remove the blank line at the end of the `# TEST` cell.