-
Notifications
You must be signed in to change notification settings - Fork 210
[MRG] Notebook CLI #148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[MRG] Notebook CLI #148
Conversation
|
@GaelVaroquaux Any comments on this one? |
|
Just curious, are you using the sphx_ex2nb.py script yourself? |
setup.py
Outdated
| package_data={'sphinx_gallery': ['_static/gallery.css', '_static/no_image.png', | ||
| '_static/broken_example.png']}, | ||
| scripts=['bin/copy_sphinxgallery.sh'], | ||
| scripts=['bin/copy_sphinxgallery.sh', 'bin/sphx_ex2nb.py'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe something less cryptic like sphx_glr_example_to_notebook? Not 100% convinced so better suggestions welcome! My point is that trying to shorten names as much as possible does not make too much sense since you have tab-completion these days ...
bin/sphx_ex2nb.py
Outdated
| args = parser.parse_args() | ||
|
|
||
| for src_file in args.file: | ||
| file_name = os.path.basename(src_file) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency I think this should be src_filename and filename. I tend to use filename for file names and file for object files (i.e. as returned from open) to make it easier to differentiate between the two.
sphinx_gallery/notebook.py
Outdated
| self.work_notebook = ipy_notebook_skeleton() | ||
| self.add_code_cell("%matplotlib inline") | ||
| self.fill_notebook(script_blocks) | ||
| self.save_file() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's generally considered best practice to have minimal logic in the constructor. In this case I would rather have an API like:
nb = Notebook(source_filename)
nb.to_notebook(target_filename)The parsing of the blocks from source_filename could happen in the constructor.
|
Comments addressed. Notebook generation is simpler now as well. And I have included test for the command line utility |
lesteve
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments:
sphinx_gallery/notebook.py
Outdated
|
|
||
| def __init__(self, file_name, target_dir): | ||
| """Declare the skeleton of the notebook | ||
| work_notebook = ipy_notebook_skeleton() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ipy_notebook -> jupyter_notebook here and everywhere else.
| """Test that written ipython notebook file corresponds to python object""" | ||
| blocks = sg.split_code_and_text_blocks('tutorials/plot_parse.py') | ||
| example_nb = jupyter_notebook(blocks) | ||
| nb_filename = "/tmp/testnb.ipynb" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not going to work on Windows. Use tempfile.NamedTemporaryFile
bin/test_cli.py
Outdated
| FileNotFoundError = IOError | ||
|
|
||
|
|
||
| class CommandLineTest(TestCase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the point of using a test class with methods rather than just functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need this class with methods because of unittest. This methods are specific to test exceptions are raised, and come inside unittest.TestCase.
To use functions I need to explicitly rely on nosetest or pytest own functions to test exceptions.
doc/utils.rst
Outdated
| Convert Python scripts into Jupyter Notebooks | ||
| ============================================= | ||
|
|
||
| Sphinx Gallery exposes its python source to Jupyter notebook convert |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
converter
.travis.yml
Outdated
| script: | ||
| - if [ "$DISTRIB" == "ubuntu" ]; then python setup.py nosetests; fi | ||
| - if [ "$DISTRIB" == "conda" ]; then nosetests; fi | ||
| - nosetests bin # to test jupyter notebook generator CLI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not very conventional ... maybe it would be great if the scripts in bin, was something super simple like:
from sphinx_gallery.notebook import main
if __name__ == '__main__':
main()This way you can still test the parser in sphinx_gallery/tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put this line because I could not get nosetest to scan the bin folder. Pytest did not have issues on that. But indeed I'll move everything to the notebook parsing file.
64276d9 to
5fb17e3
Compare
text2string into notebook to avoid circular dependence
- Converter script takes multiple files & wildcards - Install notebook converter script with setup.py
Includes the script converter and moves the gallery downloader
- Jupyter notebook generator function name is explicit
CLI inside notebook file, this allows for testing directly on the python module responsible for the rendering of the notebooks.
|
Rebased to master and comments addressed. Cleaned the commit history too |
| class CommandLineTest(TestCase): | ||
| """Test the Sphinx-Gallery python to Jupyter notebook converter CLI""" | ||
|
|
||
| def test_with_empty_args(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why still the class methods rather than functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I push a change in your branch because apart from this it is good for merging I think.
|
Merging this one, thanks! |
|
Thanks for the changes. I'm not sure if you got the comment about using the class methods for test. My idea behind it is that that is how unittest does in the standard library tests for exceptions. And since we plan to move to pytest. I did not wanted to include more use to nosetest. |
|
Oops sorry, I missed your reply somehow. In order not to have camelCase in our tests I would either the same method as in scikit-learn so that we can have def test_match():
with pytest.raises(ValueError) as excinfo:
myfunc()
excinfo.match(r'.* 123 .*') |
Don't worry about that too much, to be honest I tend to use the "Squash and merge" button these days and edit the commit message if there were too many commits and/or too many useless commit messages. |
This is a command line utility to expose sphinx gallery notebook generator.
I manually tested it on bash and zsh.
calling
sphx_ex2nb.py *.pywill convert all python files into notebooks