Merge branch 'jupyter-master'

pull/3630/head
arovitn 8 years ago
commit c37bf03655

@ -61,6 +61,33 @@ from any directory in your system with::
jupyter notebook
Verification
^^^^^^^^^^^^
While running the notebook, select one of your notebook files (the file will have the extension ``.ipynb``).
In the top tab you will click on "Help" and then click on "About". In the pop window you will see information about the version of Jupyter that you are running. You will see "The version of the notebook server is:".
If you are working in development mode, you will see that your version of Jupyter notebook will include the word "dev".
.. image:: ./docs/source/_static/images/jupyter-verification.png
:width: 40pt
If it does not include the word "dev", you are currently not working in development mode and should follow the steps below to uninstall and reinstall Jupyter.
Troubleshooting the Installation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you do not see that your Jupyter Notebook is not running on dev mode, it's possible that you are
running other instances of Jupyter Notebook. You can try the following steps:
1. Uninstall all instances of the notebook package. These include any installations you made using
pip or conda
2. Run ``python3 -m pip install -e .`` in the notebook repository to install the notebook from there
3. Run ``npm run build`` to make sure the Javascript and CSS are updated and compiled
4. Launch with ``python3 -m notebook --port 8989``, and check that the browser is pointing to ``localhost:8989``
(rather than the default 8888). You don't necessarily have to launch with port 8989, as long as you use
a port that is neither the default nor in use, then it should be fine.
5. Verify the installation with the steps in the previous section.
Rebuilding JavaScript and CSS
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

@ -15,7 +15,7 @@
"jquery-ui": "components/jqueryui#~1.10",
"marked": "~0.3",
"MathJax": "components/MathJax#~2.6",
"moment": "~2.8.4",
"moment": "~2.19.3",
"preact": "https://unpkg.com/preact@^7.2.0/dist/preact.min.js",
"preact-compat": "https://unpkg.com/preact-compat@^3.14.3/dist/preact-compat.min.js",
"proptypes": "https://unpkg.com/proptypes@^0.14.4/index.js",

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@ -0,0 +1,397 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg3390"
version="1.1"
inkscape:version="0.91 r13725"
width="705"
height="243"
viewBox="0 0 705 243"
sodipodi:docname="blank_notebook_ui.svg">
<metadata
id="metadata3396">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3394" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1855"
inkscape:window-height="1176"
id="namedview3392"
showgrid="false"
inkscape:zoom="0.86307147"
inkscape:cx="437.41347"
inkscape:cy="67.074282"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg3390" />
<image
width="705"
height="243"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,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
"
id="image3398"
x="0"
y="0" />
<g
id="g3420">
<rect
y="4.3175645"
x="209.71611"
height="33.600925"
width="265.33145"
id="rect3404"
style="opacity:0.70800045;fill:#ffffff" />
<text
sodipodi:linespacing="125%"
id="text3400"
y="29.80792"
x="217.82669"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="29.80792"
x="217.82669"
id="tspan3402"
sodipodi:role="line">⇦ Notebook name</tspan></text>
</g>
<text
sodipodi:linespacing="125%"
id="text3411"
y="70.360764"
x="415.00436"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="70.360764"
x="415.00436"
id="tspan3413"
sodipodi:role="line">Menu bar</tspan></text>
<text
sodipodi:linespacing="125%"
id="text3411-3"
y="102.85388"
x="540.51917"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="102.85388"
x="540.51917"
id="tspan3413-6"
sodipodi:role="line">Toolbar</tspan></text>
<text
sodipodi:linespacing="125%"
id="text3411-7"
y="175.849"
x="194.08205"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="175.849"
x="194.08205"
id="tspan3413-5"
sodipodi:role="line">Code cell</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -1,7 +1,7 @@
.. _changelog:
Jupyter notebook changelog
==========================
Changelog
=========
A summary of changes in the Jupyter notebook.
For more detailed information, see
@ -21,6 +21,137 @@ We strongly recommend that you upgrade to version 9+ of pip before upgrading ``n
Use ``pip install pip --upgrade`` to upgrade pip. Check pip version with
``pip --version``.
.. _release-5.5.0:
5.5.0
-----
New features:
- The files list now shows file sizes (:ghpull:`3539`)
- Add a quit button in the dashboard (:ghpull:`3004`)
- Display hostname in the terminal when running remotely (:ghpull:`3356`)
- Add slides exportation/download to the menu (:ghpull:`3287`)
- Add any extra installed nbconvert exporters to the "Download as" menu (:ghpull:`3323`)
- Editor: warning when overwriting a file that is modified on disk (:ghpull:`2783`)
- Display a warning message if cookies are not enabled (:ghpull:`3511`)
- Basic ``__version__`` reporting for extensions (:ghpull:`3541`)
- Add ``NotebookApp.terminals_enabled`` config option (:ghpull:`3478`)
- Make buffer time between last modified on disk and last modified on last save configurable (:ghpull:`3273`)
- Allow binding custom shortcuts for 'close and halt' (:ghpull:`3314`)
- Add description for 'Trusted' notification (:ghpull:`3386`)
- Add ``settings['activity_sources']`` (:ghpull:`3401`)
- Add an ``output_updated.OutputArea`` event (:ghpull:`3560`)
Fixing problems:
- Fixes to improve web accessibility (:ghpull:`3507`)
- There is more to do on this! See :ghissue:`1801`.
- Fixed color contrast issue in tree.less (:ghpull:`3336`)
- Allow cancelling upload of large files (:ghpull:`3373`)
- Don't clear login cookie on requests without cookie (:ghpull:`3380`)
- Don't trash files on different device to home dir on Linux (:ghpull:`3304`)
- Clear waiting asterisks when restarting kernel (:ghpull:`3494`)
- Fix output prompt when ``execution_count`` missing (:ghpull:`3236`)
- Make the 'changed on disk' dialog work when displayed twice (:ghpull:`3589`)
- Fix going back to root directory with history in notebook list (:ghpull:`3411`)
- Allow defining keyboard shortcuts for missing actions (:ghpull:`3561`)
- Prevent default on pageup/pagedown when completer is active (:ghpull:`3500`)
- Prevent default event handling on new terminal (:ghpull:`3497`)
- ConfigManager should not write out default values found in the .d directory (:ghpull:`3485`)
- Fix leak of iopub object in activity monitoring (:ghpull:`3424`)
- Javascript lint in notebooklist.js (:ghpull:`3409`)
- Some Javascript syntax fixes (:ghpull:`3294`)
- Convert native for loop to ``Array.forEach()`` (:ghpull:`3477`)
- Disable cache when downloading nbconvert output (:ghpull:`3484`)
- Add missing digestmod arg to HMAC (:ghpull:`3399`)
- Log OSErrors failing to create less-critical files during startup (:ghpull:`3384`)
- Use powershell on Windows (:ghpull:`3379`)
- API spec improvements, API handler improvements (:ghpull:`3368`)
- Set notebook to dirty state after change to kernel metadata (:ghpull:`3350`)
- Use CSP header to treat served files as belonging to a separate origin (:ghpull:`3341`)
- Don't install gettext into builtins (:ghpull:`3330`)
- Add missing ``import _`` (:ghpull:`3316`, :ghpull:`3326`)
- Write ``notebook.json`` file atomically (:ghpull:`3305`)
- Fix clicking with modifiers, page title updates (:ghpull:`3282`)
- Upgrade jQuery to version 2.2 (:ghpull:`3428`)
- Upgrade xterm.js to 3.1.0 (:ghpull:`3189`)
- Upgrade moment.js to 2.19.3 (:ghpull:`3562`)
- Upgrade CodeMirror to 5.35 (:ghpull:`3372`)
- "Require" pyzmq>=17 (:ghpull:`3586`)
Documentation:
- Documentation updates and organisation (:ghpull:`3584`)
- Add section in docs about privacy (:ghpull:`3571`)
- Add explanation on how to change the type of a cell to Markdown (:ghpull:`3377`)
- Update docs with confd implementation details (:ghpull:`3520`)
- Add more information for where ``jupyter_notebook_config.py`` is located (:ghpull:`3346`)
- Document options to enable nbextensions in specific sections (:ghpull:`3525`)
- jQuery attribute selector value MUST be surrounded by quotes (:ghpull:`3527`)
- Do not execute special notebooks with nbsphinx (:ghpull:`3360`)
- Other minor fixes in :ghpull:`3288`, :ghpull:`3528`, :ghpull:`3293`, :ghpull:`3367`
Testing:
- Testing with Selenium & Sauce labs (:ghpull:`3321`)
- Selenium utils + markdown rendering tests (:ghpull:`3458`)
- Convert insert cell tests to Selenium (:ghpull:`3508`)
- Convert prompt numbers tests to Selenium (:ghpull:`3554`)
- Convert delete cells tests to Selenium (:ghpull:`3465`)
- Convert undelete cell tests to Selenium (:ghpull:`3475`)
- More selenium testing utilities (:ghpull:`3412`)
- Only check links when build is trigger by Travis Cron job (:ghpull:`3493`)
- Fix Appveyor build errors (:ghpull:`3430`)
- Undo patches in teardown before attempting to delete files (:ghpull:`3459`)
- Get tests running with tornado 5 (:ghpull:`3398`)
- Unpin ipykernel version on Travis (:ghpull:`3223`)
Thanks to the following contributors:
- Arovit Narula (`arovit <https://github.com/arovit>`__)
- Ashley Teoh (`ashleytqy <https://github.com/ashleytqy>`__)
- Nicholas Bollweg (`bollwyvl <https://github.com/bollwyvl>`__)
- Alex Rothberg (`cancan101 <https://github.com/cancan101>`__)
- Celina Kilcrease (`ckilcrease <https://github.com/ckilcrease>`__)
- dabuside (`dabuside <https://github.com/dabuside>`__)
- Damian Avila (`damianavila <https://github.com/damianavila>`__)
- Dana Lee (`danagilliann <https://github.com/danagilliann>`__)
- Dave Hirschfeld (`dhirschfeld <https://github.com/dhirschfeld>`__)
- Heng GAO (`ehengao <https://github.com/ehengao>`__)
- Leo Gallucci (`elgalu <https://github.com/elgalu>`__)
- Evan Van Dam (`evandam <https://github.com/evandam>`__)
- forbxy (`forbxy <https://github.com/forbxy>`__)
- Grant Nestor (`gnestor <https://github.com/gnestor>`__)
- Ethan T. Hendrix (`hendrixet <https://github.com/hendrixet>`__)
- Miro Hrončok (`hroncok <https://github.com/hroncok>`__)
- Paul Ivanov (`ivanov <https://github.com/ivanov>`__)
- Darío Hereñú (`kant <https://github.com/kant>`__)
- Kevin Bates (`kevin-bates <https://github.com/kevin-bates>`__)
- Maarten Breddels (`maartenbreddels <https://github.com/maartenbreddels>`__)
- Michael Droettboom (`mdboom <https://github.com/mdboom>`__)
- Min RK (`minrk <https://github.com/minrk>`__)
- M Pacer (`mpacer <https://github.com/mpacer>`__)
- Peter Parente (`parente <https://github.com/parente>`__)
- Paul Masson (`paulmasson <https://github.com/paulmasson>`__)
- Philipp Rudiger (`philippjfr <https://github.com/philippjfr>`__)
- Mac Knight (`Shels1909 <https://github.com/Shels1909>`__)
- Hisham Elsheshtawy (`Sheshtawy <https://github.com/Sheshtawy>`__)
- Simon Biggs (`SimonBiggs <https://github.com/SimonBiggs>`__)
- Sunil Hari (`sunilhari <https://github.com/sunilhari>`__)
- Thomas Kluyver (`takluyver <https://github.com/takluyver>`__)
- Tim Klever (`tklever <https://github.com/tklever>`__)
- Gabriel Ruiz (`unnamedplay-r <https://github.com/unnamedplay-r>`__)
- Vaibhav Sagar (`vaibhavsagar <https://github.com/vaibhavsagar>`__)
- William Hosford (`whosford <https://github.com/whosford>`__)
- Hong (`xuhdev <https://github.com/xuhdev>`__)
See the 5.5 milestone on GitHub for a complete list of
`pull requests <https://github.com/jupyter/notebook/pulls?utf8=%E2%9C%93&q=is%3Apr%20milestone%3A5.5>`__ involved in this release.
.. _release-5.4.1:
5.4.1

@ -31,7 +31,7 @@
"metadata": {},
"source": [
"### Why create a Python package for Jupyter extensions?\n",
"Since it is rare to have a server extension that does not have any frontend components (an nbextension), for convenience and consistency, all these client and server extensions with their assets can be packaged and versioned together as a Python package with a few simple commands. This makes installing the package of extensions easier and less error-prone for the user. "
"Since it is rare to have a server extension that does not have any frontend components (an nbextension), for convenience and consistency, all these client and server extensions with their assets can be packaged and versioned together as a Python package with a few simple commands, or as of Notebook 5.3, handled automatically by your package manager of choice. This makes installing the package of extensions easier and less error-prone for the user."
]
},
{
@ -52,6 +52,16 @@
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Automatic installation and Enabling\n",
"> New in Notebook 5.3\n",
"\n",
"The absolute simplest case requires no user interaction at all! Configured correctly, after installing with their package manager of choice, both server and frontend extensions can be enabled by default in the environment where they were installed, i.e. `--sys-prefix`. See the `setup.py` in the example below."
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -259,6 +269,130 @@
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Automatically enabling a server extension and nbextension\n",
"> New in Notebook 5.3\n",
"\n",
"Server extensions and nbextensions can be installed and enabled without any user intervention or post-install scripts beyond `<package manager> install <extension package name>`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In addition to the `my_fancy_module` file tree, assume:\n",
"- `jupyter-config/`\n",
" - `jupyter_notebook_config.d/`\n",
" - `my_fancy_module.json`\n",
" - `nbconfig/`\n",
" - `notebook.d/`\n",
" - `my_fancy_module.json`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `jupyter-config/jupyter_notebook_config.d/my_fancy_module.json`\n",
"```json\n",
"{\n",
" \"NotebookApp\": {\n",
" \"nbserver_extensions\": {\n",
" \"my_fancy_module\": true\n",
" }\n",
" }\n",
"}\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `jupyter-config/nbconfig/notebook.d/my_fancy_module.json`\n",
"```json\n",
"{\n",
" \"load_extensions\": {\n",
" \"my_fancy_module/index\": true\n",
" }\n",
"}\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Put all of them in place via:\n",
"\n",
"#### `setup.py`\n",
"```python\n",
"import setuptools\n",
"\n",
"setuptools.setup(\n",
" name=\"MyFancyModule\",\n",
" ...\n",
" include_package_data=True,\n",
" data_files=[\n",
" # like `jupyter nbextension install --sys-prefix`\n",
" (\"share/jupyter/nbextensions/my_fancy_module\", [\n",
" \"my_fancy_module/static/index.js\",\n",
" ]),\n",
" # like `jupyter nbextension enable --sys-prefix`\n",
" (\"etc/jupyter/nbconfig/notebook.d\", [\n",
" \"jupyter-config/nbconfig/notebook.d/my_fancy_module.json\"\n",
" ]),\n",
" # like `jupyter serverextension enable --sys-prefix`\n",
" (\"etc/jupyter/jupyter_notebook_config.d\", [\n",
" \"jupyter-config/jupyter_notebook_config.d/my_fancy_module.json\"\n",
" ])\n",
" ],\n",
" ...\n",
" zip_safe=False\n",
")\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"and last, but not least:\n",
"\n",
"#### `MANIFEST.in`\n",
"```config\n",
"recursive-include jupyter-config *.json\n",
"recursive-include my_fancy_module/static *.js\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As most package managers will only modify their environment, the eventual configuration will be as if the user had typed:\n",
"```\n",
"jupyter nbextension install --py my_fancy_module --sys-prefix\n",
"jupyter nbextension enable --py my_fancy_module --sys-prefix\n",
"jupyter serverextension enable --py my_fancy_module --sys-prefix\n",
"```\n",
"\n",
"If a user manually `disable`s an extension, that configuration will override the bundled package configuration."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### When automagical install fails\n",
"Note this can still fail in certain situations with `pip`, requiring manual use of `install` and `enable` commands.\n",
"\n",
"Non-python-specific package managers (e.g. `conda`, `apt`) may choose not to implement the above behavior at the `setup.py` level, having more ways to put data files in various places at build time."
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -368,7 +502,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.1"
"version": "3.6.5"
}
},
"nbformat": 4,

@ -1,14 +1,13 @@
`View the original notebooks on nbviewer`__
=================
Notebook Examples
=================
The pages in this section are all converted notebook files. You can also
`view these notebooks on nbviewer`__.
__ http://nbviewer.jupyter.org/github/jupyter/notebook/blob/master/
docs/source/examples/Notebook/
========
Examples
========
The following notebooks have been rendered for your convenience.
.. toctree::
:maxdepth: 2

@ -1,20 +1,23 @@
====================
The Jupyter notebook
The Jupyter Notebook
====================
* `Installation <https://jupyter.readthedocs.io/en/latest/install.html>`_
* `Starting the Notebook <https://jupyter.readthedocs.io/en/latest/running.html>`_
.. toctree::
:maxdepth: 1
:caption: User Documentation
notebook
Installation <https://jupyter.readthedocs.io/en/latest/install.html>
Running the Notebook <https://jupyter.readthedocs.io/en/latest/running.html>
Migrating from IPython <https://jupyter.readthedocs.io/en/latest/migrating.html>
ui_components
examples/Notebook/examples_index.rst
troubleshooting
changelog
comms
.. toctree::
:maxdepth: 2
:maxdepth: 1
:caption: Configuration
config_overview
@ -33,38 +36,8 @@ The Jupyter notebook
development_release
development_faq
.. toctree::
:maxdepth: 1
:caption: Community documentation
examples/Notebook/examples_index.rst
examples/Notebook/What is the Jupyter Notebook
examples/Notebook/Notebook Basics
examples/Notebook/Running Code
examples/Notebook/Working With Markdown Cells
examples/Notebook/Custom Keyboard Shortcuts
examples/Notebook/JavaScript Notebook Extensions
examples/Notebook/Importing Notebooks
examples/Notebook/Connecting with the Qt Console
examples/Notebook/Typesetting Equations
.. toctree::
:hidden:
examples/Notebook/nbpackage/mynotebook.ipynb
examples/Notebook/nbpackage/nbs/other.ipynb
.. toctree::
:maxdepth: 2
:caption: About Jupyter Notebook
changelog
.. toctree::
:maxdepth: 1
:caption: Questions? Suggestions?
Jupyter mailing list <https://groups.google.com/forum/#!forum/jupyter>
Jupyter website <https://jupyter.org>
Stack Overflow - Jupyter <https://stackoverflow.com/questions/tagged/jupyter>
Stack Overflow - Jupyter-notebook <https://stackoverflow.com/questions/tagged/jupyter-notebook>

@ -83,6 +83,29 @@ without relying on nbviewer.
:ref:`Details on the notebook JSON file format <nbformat:notebook_file_format>`
Notebooks and privacy
~~~~~~~~~~~~~~~~~~~~~
Because you use Jupyter in a web browser, some people are understandably
concerned about using it with sensitive data.
However, if you followed the standard
`install instructions <https://jupyter.readthedocs.io/en/latest/install.html>`_,
Jupyter is actually running on your own computer.
If the URL in the address bar starts with ``http://localhost:`` or
``http://127.0.0.1:``, it's your computer acting as the server.
Jupyter doesn't send your data anywhere else—and as it's open source,
other people can check that we're being honest about this.
You can also use Jupyter remotely:
your company or university might run the server for you, for instance.
If you want to work with sensitive data in those cases,
talk to your IT or data protection staff about it.
We aim to ensure that other pages in your browser or other users on the same
computer can't access your notebook server. See :ref:`server_security` for
more about this.
Starting the notebook server
----------------------------
@ -177,32 +200,24 @@ Notebook user interface
-----------------------
When you create a new notebook document, you will be presented with the
**notebook name**, a **menu bar**, a **toolbar** and an empty **code
cell**.
**notebook name**, a **menu bar**, a **toolbar** and an empty **code cell**.
**notebook name**: The name of the notebook document is displayed at the top
of the page, next to the ``IP[y]: Notebook`` logo. This name reflects the name
of the ``.ipynb`` notebook document file. Clicking on the notebook name
brings up a dialog which allows you to rename it. Thus, renaming a notebook
.. image:: ./_static/images/blank-notebook-ui.png
**Notebook name**: The name displayed at the top of the page,
next to the Jupyter logo, reflects the name of the ``.ipynb`` file.
Clicking on the notebook name brings up a dialog which allows you to rename it.
Thus, renaming a notebook
from "Untitled0" to "My first notebook" in the browser, renames the
``Untitled0.ipynb`` file to ``My first notebook.ipynb``.
**menu bar**: The menu bar presents different options that may be used to
**Menu bar**: The menu bar presents different options that may be used to
manipulate the way the notebook functions.
**toolbar**: The tool bar gives a quick way of performing the most-used
**Toolbar**: The tool bar gives a quick way of performing the most-used
operations within the notebook, by clicking on an icon.
**code cell**: the default type of cell, read on for an explanation of cells
.. note::
As of notebook version 4.1, the user interface allows for multiple cells to
be selected. The ``quick celltype selector``, found in the menubar, will
display a dash ``-`` when multiple cells are selected to indicate that the
type of the cells in the selection might not be unique. The quick selector
can still be used to change the type of the selection and will change the
type of all the currently selected cells.
**Code cell**: the default type of cell; read on for an explanation of cells.
Structure of a notebook document
@ -210,7 +225,7 @@ Structure of a notebook document
The notebook consists of a sequence of cells. A cell is a multiline text input
field, and its contents can be executed by using :kbd:`Shift-Enter`, or by
clicking either the "Play" button the toolbar, or `Cell | Run` in the menu bar.
clicking either the "Play" button the toolbar, or :guilabel:`Cell`, :guilabel:`Run` in the menu bar.
The execution behavior of a cell is determined by the cell's type. There are three
types of cells: **code cells**, **markdown cells**, and **raw cells**. Every
cell starts off being a **code cell**, but its type can be changed by using a
@ -224,9 +239,8 @@ see the `collection of examples
Code cells
~~~~~~~~~~
A *code cell* allows you to edit and write new code, with full syntax
highlighting and tab completion. By default, the language associated to a code
cell is Python, but other languages, such as ``Julia`` and ``R``, can be
handled using :ref:`cell magic commands <magics_explained>`.
highlighting and tab completion. The programming language you use depends
on the *kernel*, and the default kernel (IPython) runs Python code.
When a code cell is executed, code that it contains is sent to the kernel
associated with the notebook. The results that are returned from this
@ -269,7 +283,7 @@ supports a `large subset <mathjax_tex>`_ of LaTeX functionality
.. _mathjax_tex: https://docs.mathjax.org/en/latest/tex.html
Standard mathematics environments defined by LaTeX and AMS-LaTeX (the
`amsmath` package) also work, such as
``amsmath`` package) also work, such as
``\begin{equation}...\end{equation}``, and ``\begin{align}...\end{align}``.
New LaTeX macros may be defined using standard methods,
such as ``\newcommand``, by placing them anywhere *between math delimiters* in
@ -286,7 +300,7 @@ Raw cells
*Raw* cells provide a place in which you can write *output* directly.
Raw cells are not evaluated by the notebook.
When passed through nbconvert_, raw cells arrive in the
destination format unmodified. For example, this allows you to type full LaTeX
destination format unmodified. For example, you can type full LaTeX
into a raw cell, which will only be rendered by LaTeX after conversion by
nbconvert.
@ -306,17 +320,14 @@ correctly. This is much more convenient for interactive exploration than
breaking up a computation into scripts that must be executed together, as was
previously necessary, especially if parts of them take a long time to run.
At certain moments, it may be necessary to interrupt a calculation which is
taking too long to complete. This may be done with the `Kernel | Interrupt`
menu option, or the :kbd:`Ctrl-m i` keyboard shortcut.
Similarly, it may be necessary or desirable to restart the whole computational
process, with the `Kernel | Restart` menu option or :kbd:`Ctrl-m .`
To interrupt a calculation which is taking too long, use the :guilabel:`Kernel`,
:guilabel:`Interrupt` menu option, or the :kbd:`i,i` keyboard shortcut.
Similarly, to restart the whole computational process,
use the :guilabel:`Kernel`, :guilabel:`Restart` menu option or :kbd:`0,0`
shortcut.
A notebook may be downloaded in either a ``.ipynb`` or ``.py`` file from the
menu option `File | Download as`. Choosing the ``.py`` option downloads a
Python ``.py`` script, in which all rich output has been removed and the
content of markdown cells have been inserted as comments.
A notebook may be downloaded as a ``.ipynb`` file or converted to a number of
other formats using the menu option :guilabel:`File`, :guilabel:`Download as`.
.. seealso::
@ -333,31 +344,16 @@ shortcuts are also available for the most common ones. The essential shortcuts
to remember are the following:
* :kbd:`Shift-Enter`: run cell
Execute the current cell, show output (if any), and jump to the next cell
below. If :kbd:`Shift-Enter` is invoked on the last cell, a new code
cell will also be created. Note that in the notebook, typing :kbd:`Enter`
on its own *never* forces execution, but rather just inserts a new line in
the current cell. :kbd:`Shift-Enter` is equivalent to clicking the
``Cell | Run`` menu item.
* :kbd:`Ctrl-Enter`: run cell in-place
Execute the current cell as if it were in "terminal mode", where any
output is shown, but the cursor *remains* in the current cell. The cell's
entire contents are selected after execution, so you can just start typing
and only the new input will be in the cell. This is convenient for doing
quick experiments in place, or for querying things like filesystem
content, without needing to create additional cells that you may not want
to be saved in the notebook.
* :kbd:`Alt-Enter`: run cell, insert below
Executes the current cell, shows the output, and inserts a *new*
cell between the current cell and the cell below (if one exists). This
is thus a shortcut for the sequence :kbd:`Shift-Enter`, :kbd:`Ctrl-m a`.
(:kbd:`Ctrl-m a` adds a new cell above the current one.)
* :kbd:`Esc` and :kbd:`Enter`: Command mode and edit mode
In command mode, you can easily navigate around the notebook using keyboard
shortcuts. In edit mode, you can edit text in cells.
Execute the current cell, show any output, and jump to the next cell below.
If :kbd:`Shift-Enter` is invoked on the last cell, it makes a new cell below.
This is equivalent to clicking the :guilabel:`Cell`, :guilabel:`Run` menu
item, or the Play button in the toolbar.
* :kbd:`Esc`: Command mode
In command mode, you can navigate around the notebook using keyboard shortcuts.
* :kbd:`Enter`: Edit mode
In edit mode, you can edit text in cells.
For the full list of available shortcuts, click :guilabel:`Help`,
:guilabel:`Keyboard Shortcuts` in the notebook menus.
@ -375,64 +371,49 @@ Installing kernels
For information on how to install a Python kernel, refer to the
`IPython install page <https://ipython.org/install.html>`__.
Kernels for other languages can be found in the `IPython wiki
<https://github.com/ipython/ipython/wiki/IPython%20kernels%20for%20other%20languages>`_.
They usually come with instruction what to run to make the kernel available
The Jupyter wiki has a long list of `Kernels for other languages
<https://github.com/jupyter/jupyter/wiki/Jupyter-kernels>`_.
They usually come with instructions on how to make the kernel available
in the notebook.
.. _signing_notebooks:
Signing Notebooks
-----------------
Trusting Notebooks
------------------
To prevent untrusted code from executing on users' behalf when notebooks open,
we have added a signature to the notebook, stored in metadata.
we store a signature of each trusted notebook.
The notebook server verifies this signature when a notebook is opened.
If the signature stored in the notebook metadata does not match,
javascript and HTML output will not be displayed on load,
and must be regenerated by re-executing the cells.
If no matching signature is found,
Javascript and HTML output will not be displayed
until they are regenerated by re-executing the cells.
Any notebook that you have executed yourself *in its entirety* will be
considered trusted, and its HTML and javascript output will be displayed on
Any notebook that you have fully executed yourself will be
considered trusted, and its HTML and Javascript output will be displayed on
load.
If you need to see HTML or Javascript output without re-executing,
you can explicitly trust notebooks, such as those shared with you,
or those that you have written yourself prior to IPython 2.0,
and you are sure the notebook is not malicious, you can tell Jupyter to trust it
at the command-line with::
$ jupyter trust mynotebook.ipynb [other notebooks.ipynb]
This just generates a new signature stored in each notebook.
You can generate a new notebook signing key with::
$ jupyter trust --reset
$ jupyter trust mynotebook.ipynb
.. include:: links.txt
See :ref:`notebook_security` for more details about the trust mechanism.
Browser Compatibility
---------------------
The Jupyter Notebook is officially supported by the latest stable versions of the
following browsers:
The Jupyter Notebook aims to support the latest versions of these browsers:
* Chrome
* Safari
* Firefox
The is mainly due to the notebook's usage of WebSockets and the flexible box
model.
The following browsers are unsupported:
* Safari < 5
* Firefox < 6
* Chrome < 13
* Opera (any): CSS issues, but execution might work
* Internet Explorer < 10
* Internet Explorer ≥ 10 (same as Opera)
Up to date versions of Opera and Edge may also work, but if they don't, please
use one of the supported browsers.
Using Safari with HTTPS and an untrusted certificate is known to not work
(websockets will fail).
.. include:: links.txt

@ -0,0 +1,87 @@
What to do when things go wrong
===============================
First, have a look at the common problems listed below. If you can figure it out
from these notes, it will be quicker than asking for help.
Check that you have the latest version of any packages that look relevant.
Unfortunately it's not always easy to figure out what packages are relevant,
but if there was a bug that's already been fixed,
it's easy to upgrade and get on with what you wanted to do.
Jupyter fails to start
----------------------
* Have you `installed it <http://jupyter.org/install.html>`__? ;-)
* If you're using a menu shortcut or Anaconda launcher to start it, try
opening a terminal or command prompt and running the command ``jupyter notebook``.
* If it can't find ``jupyter``,
you may need to configure your ``PATH`` environment variable.
If you don't know what that means, and don't want to find out,
just (re)install Anaconda with the default settings,
and it should set up PATH correctly.
* If Jupyter gives an error that it can't find ``notebook``,
check with pip or conda that the ``notebook`` package is installed.
* Try running ``jupyter-notebook`` (with a hyphen). This should normally be the
same as ``jupyter notebook`` (with a space), but if there's any difference,
the version with the hyphen is the 'real' launcher, and the other one wraps
that.
Jupyter doesn't load or doesn't work in the browser
---------------------------------------------------
* Try in another browser (e.g. if you normally use Firefox, try with Chrome).
This helps pin down where the problem is.
* Try disabling any browser extensions and/or any Jupyter extensions you have
installed.
* Some internet security software can interfere with Jupyter.
If you have security software, try turning it off temporarily,
and look in the settings for a more long-term solution.
* In the address bar, try changing between ``localhost`` and ``127.0.0.1``.
They should be the same, but in some cases it makes a difference.
Jupyter can't start a kernel
----------------------------
Files called *kernel specs* tell Jupyter how to start different kinds of kernel.
To see where these are on your system, run ``jupyter kernelspec list``::
$ jupyter kernelspec list
Available kernels:
python3 /home/takluyver/.local/lib/python3.6/site-packages/ipykernel/resources
bash /home/takluyver/.local/share/jupyter/kernels/bash
ir /home/takluyver/.local/share/jupyter/kernels/ir
There's a special fallback for the Python kernel:
if it doesn't find a real kernelspec, but it can import the ``ipykernel`` package,
it provides a kernel which will run in the same Python environment as the notebook server.
A path ending in ``ipykernel/resources``, like in the example above,
is this default kernel.
The default often does what you want,
so if the ``python3`` kernelspec points somewhere else
and you can't start a Python kernel,
try deleting or renaming that kernelspec folder to expose the default.
If your problem is with another kernel, not the Python one we maintain,
you may need to look for support about that kernel.
Asking for help
---------------
As with any problem, try searching to see if someone has already found an answer.
If you can't find an existing answer, you can ask questions at:
* The `jupyter-notebook tag on Stackoverflow <https://stackoverflow.com/questions/tagged/jupyter-notebook>`_
* The `jupyter/help repository on Github <https://github.com/jupyter/help>`_
* Or in an issue on another repository, if it's clear which component is
responsible.
Don't forget to provide details. What error messages do you see?
What platform are you on? How did you install Jupyter?
What have you tried already?
The ``jupyter troubleshoot`` command collects a lot of information
about your installation, which can be useful.
Remember that it's not anyone's job to help you.
We want Jupyter to work for you,
but we can't always help everyone individually.

@ -1,5 +1,6 @@
UI Components
=============
User interface components
=========================
When opening bug reports or sending emails to the Jupyter mailing list, it is
useful to know the names of different UI components so that other developers
and users have an easier time helping you diagnose your problems. This section

@ -9,6 +9,7 @@ import glob
import io
import json
import os
import copy
from six import PY3
from traitlets.config import LoggingConfigurable
@ -36,9 +37,23 @@ def recursive_update(target, new):
target[k] = v
def remove_defaults(data, defaults):
"""Recursively remove items from dict that are already in defaults"""
# copy the iterator, since data will be modified
for key, value in list(data.items()):
if key in defaults:
if isinstance(value, dict):
remove_defaults(data[key], defaults[key])
if not data[key]: # prune empty subdicts
del data[key]
else:
if value == defaults[key]:
del data[key]
class BaseJSONConfigManager(LoggingConfigurable):
"""General JSON config manager
Deals with persisting/storing config in a json file with optionally
default values in a {section_name}.d directory.
"""
@ -62,19 +77,22 @@ class BaseJSONConfigManager(LoggingConfigurable):
"""Returns the directory name for the section name: {config_dir}/{section_name}.d"""
return os.path.join(self.config_dir, section_name+'.d')
def get(self, section_name):
def get(self, section_name, include_root=True):
"""Retrieve the config data for the specified section.
Returns the data as a dictionary, or an empty dictionary if the file
doesn't exist.
When include_root is False, it will not read the root .json file,
effectively returning the default values.
"""
paths = [self.file_name(section_name)]
paths = [self.file_name(section_name)] if include_root else []
if self.read_directory:
pattern = os.path.join(self.directory(section_name), '*.json')
# These json files should be processed first so that the
# {section_name}.json take precedence.
# The idea behind this is that installing a Python package may
# put a json file somewhere in the a .d directory, while the
# put a json file somewhere in the a .d directory, while the
# .json file is probably a user configuration.
paths = sorted(glob.glob(pattern)) + paths
self.log.debug('Paths used for configuration of %s: \n\t%s', section_name, '\n\t'.join(paths))
@ -91,6 +109,12 @@ class BaseJSONConfigManager(LoggingConfigurable):
filename = self.file_name(section_name)
self.ensure_config_dir_exists()
if self.read_directory:
# we will modify data in place, so make a copy
data = copy.deepcopy(data)
defaults = self.get(section_name, include_root=False)
remove_defaults(data, defaults)
# Generate the JSON up front, since it could raise an exception,
# in order to avoid writing half-finished corrupted data to disk.
json_content = json.dumps(data, indent=2)

@ -218,18 +218,17 @@ define([
* Flatten a tree of shortcut sequences.
* use full to iterate over all the key/values of available shortcuts.
**/
var dct = {};
for(var key in tree){
var value = tree[key];
var dct = {};
_.forEach(tree, function(value, key) {
if(typeof(value) === 'string'){
dct[key] = value;
} else {
var ftree=flatten_shorttree(value);
for(var subkey in ftree){
_.forEach(ftree, function(v2, subkey) {
dct[key+','+subkey] = ftree[subkey];
}
});
}
}
});
return dct;
};
@ -237,40 +236,39 @@ define([
ShortcutManager.prototype.get_action_shortcuts = function(name){
var ftree = flatten_shorttree(this._shortcuts);
var res = [];
for (var sht in ftree ){
if(ftree[sht] === name){
res.push(sht);
_.forEach(ftree, function(value, key) {
if(value === name){
res.push(key);
}
}
});
return res;
};
ShortcutManager.prototype.get_action_shortcut = function(name){
var ftree = flatten_shorttree(this._shortcuts);
for (var sht in ftree ){
if(ftree[sht] === name){
return sht;
}
var matches = this.get_action_shortcuts(name);
if (matches.length > 0) {
return matches[0];
}
return undefined;
};
ShortcutManager.prototype.help = function () {
var that = this;
var help = [];
var ftree = flatten_shorttree(this._shortcuts);
for (var shortcut in ftree) {
var action = this.actions.get(ftree[shortcut]);
_.forEach(ftree, function(value, key) {
var action = that.actions.get(value);
var help_string = action.help||'== no help ==';
var help_index = action.help_index;
if (help_string) {
var shortstring = (action.shortstring||shortcut);
var shortstring = (action.shortstring||key);
help.push({
shortcut: shortstring,
help: help_string,
help_index: help_index}
);
}
}
});
help.sort(function (a, b) {
if (a.help_index === b.help_index) {
if (a.shortcut === b.shortcut) {
@ -366,7 +364,7 @@ define([
if(current_node === undefined){
return true;
} else {
if (typeof(current_node) == 'string'){
if (typeof(current_node) === 'string'){
return false;
} else { // assume is a sub-shortcut tree
return this._is_available_shortcut(shortcut_array.slice(1), current_node);
@ -404,7 +402,6 @@ define([
shortcut = shortcut.toLowerCase();
this.add_shortcut(shortcut, data);
var patch = {keys:{}};
var b = {bind:{}};
patch.keys[this._mode] = {bind:{}};
patch.keys[this._mode].bind[shortcut] = data;
this._config.update(patch);
@ -418,7 +415,6 @@ define([
shortcut = shortcut.toLowerCase();
this.remove_shortcut(shortcut);
var patch = {keys: {}};
var b = {bind: {}};
patch.keys[this._mode] = {bind:{}};
patch.keys[this._mode].bind[shortcut] = null;
this._config.update(patch);
@ -454,7 +450,14 @@ define([
**/
var action_name = this.actions.get_name(data);
if (! action_name){
throw new Error('does not know how to deal with : ' + data);
if (typeof data === 'string') {
// If we have an action name, allow it to be bound anyway.
console.log("Unknown action '" + data + "' for shortcut " + shortcut
+ "; it may be defined by an extension which is not yet loaded.");
action_name = data;
} else {
throw new Error('does not know how to deal with : ' + data);
}
}
var _shortcut = normalize_shortcut(shortcut);
this.set_shortcut(_shortcut, action_name);
@ -471,9 +474,10 @@ define([
*
* data : Dict of the form {key:value, ...}
**/
for (var shortcut in data) {
this.add_shortcut(shortcut, data[shortcut], true);
}
var that = this;
_.forEach(data, function(value, key) {
that.add_shortcut(key, value, true);
});
// update the keyboard shortcuts notebook help
this.events.trigger('rebuild.QuickHelp');
};
@ -560,7 +564,7 @@ define([
return (typeof(action_name) !== 'undefined');
};
var keyboard = {
return {
keycodes : keycodes,
inv_keycodes : inv_keycodes,
ShortcutManager : ShortcutManager,
@ -569,6 +573,4 @@ define([
shortcut_to_event : shortcut_to_event,
event_to_shortcut : event_to_shortcut,
};
return keyboard;
});

@ -2761,6 +2761,8 @@ define([
if (that._changed_on_disk_dialog !== null) {
// update save callback on the confirmation button
that._changed_on_disk_dialog.find('.save-confirm-btn').click(_save);
//Rebind Click Event on Reload
that._changed_on_disk_dialog.find('.btn-warning').click(function () {window.location.reload()});
// redisplay existing dialog
that._changed_on_disk_dialog.modal('show');
} else {

@ -631,6 +631,10 @@ define([
(json.data[MIME_MARKDOWN] !== undefined)) {
this.typeset();
}
this.events.trigger('output_updated.OutputArea', {
output: json,
output_area: this,
});
};
OutputArea.prototype._record_display_id = function (json, element) {

@ -1,82 +0,0 @@
// Test
casper.notebook_test(function () {
var a = 'print("a")';
var index = this.append_cell(a);
this.execute_cell_then(index);
var b = 'print("b")';
index = this.append_cell(b);
this.execute_cell_then(index);
var c = 'print("c")';
index = this.append_cell(c);
this.execute_cell_then(index);
this.thenEvaluate(function() {
IPython.notebook.default_cell_type = 'code';
});
this.then(function () {
// Cell insertion
this.select_cell(2);
this.trigger_keydown('m'); // Make it markdown
this.trigger_keydown('a'); // Creates one cell
this.test.assertEquals(this.get_cell_text(2), '', 'a; New cell 2 text is empty');
this.test.assertEquals(this.get_cell(2).cell_type, 'code', 'a; inserts a code cell');
this.validate_notebook_state('a', 'command', 2);
this.trigger_keydown('b'); // Creates one cell
this.test.assertEquals(this.get_cell_text(2), '', 'b; Cell 2 text is still empty');
this.test.assertEquals(this.get_cell_text(3), '', 'b; New cell 3 text is empty');
this.test.assertEquals(this.get_cell(3).cell_type, 'code', 'b; inserts a code cell');
this.validate_notebook_state('b', 'command', 3);
});
this.thenEvaluate(function() {
IPython.notebook.class_config.set('default_cell_type', 'selected');
});
this.then(function () {
this.select_cell(2);
this.trigger_keydown('m'); // switch it to markdown for the next test
this.test.assertEquals(this.get_cell(2).cell_type, 'markdown', 'test cell is markdown');
this.trigger_keydown('a'); // new cell above
this.test.assertEquals(this.get_cell(2).cell_type, 'markdown', 'a; inserts a markdown cell when markdown selected');
this.trigger_keydown('b'); // new cell below
this.test.assertEquals(this.get_cell(3).cell_type, 'markdown', 'b; inserts a markdown cell when markdown selected');
});
this.thenEvaluate(function() {
IPython.notebook.class_config.set('default_cell_type', 'above');
});
this.then(function () {
this.select_cell(2);
this.trigger_keydown('y'); // switch it to code for the next test
this.test.assertEquals(this.get_cell(2).cell_type, 'code', 'test cell is code');
this.trigger_keydown('b'); // new cell below
this.test.assertEquals(this.get_cell(3).cell_type, 'code', 'b; inserts a code cell below code cell');
this.trigger_keydown('a'); // new cell above
this.test.assertEquals(this.get_cell(3).cell_type, 'code', 'a; inserts a code cell above code cell');
});
this.then(function () {
this.set_cell_text(1, 'cell1');
this.select_cell(1);
this.select_cell(2, false);
this.trigger_keydown('a');
this.test.assertEquals(this.get_cell_text(1), '', 'a; New cell 1 text is empty');
this.test.assertEquals(this.get_cell_text(2), 'cell1', 'a; Cell 2 text is old cell 1');
this.set_cell_text(1, 'cell1');
this.set_cell_text(2, 'cell2');
this.set_cell_text(3, 'cell3');
this.select_cell(1);
this.select_cell(2, false);
this.trigger_keydown('b');
this.test.assertEquals(this.get_cell_text(1), 'cell1', 'b; Cell 1 remains');
this.test.assertEquals(this.get_cell_text(2), 'cell2', 'b; Cell 2 remains');
this.test.assertEquals(this.get_cell_text(3), '', 'b; Cell 3 is new');
this.test.assertEquals(this.get_cell_text(4), 'cell3', 'b; Cell 4 text is old cell 3');
});
});

@ -1,5 +1,3 @@
import os
import pytest
def cell_is_deletable(nb, index):
JS = 'return Jupyter.notebook.get_cell({}).is_deletable();'.format(index)

@ -0,0 +1,57 @@
from selenium.webdriver.common.keys import Keys
from .utils import shift
def test_insert_cell(notebook):
a = "print('a')"
b = "print('b')"
c = "print('c')"
notebook.edit_cell(index=0, content=a)
notebook.append(b, c)
notebook.to_command_mode()
assert notebook.get_cells_contents() == [a, b, c]
notebook.to_command_mode()
notebook.focus_cell(2)
notebook.convert_cell_type(2, "markdown")
# insert code cell above
notebook.current_cell.send_keys("a")
assert notebook.get_cell_contents(2) == ""
assert notebook.get_cell_type(2) == "code"
assert len(notebook.cells) == 4
# insert code cell below
notebook.current_cell.send_keys("b")
assert notebook.get_cell_contents(2) == ""
assert notebook.get_cell_contents(3) == ""
assert notebook.get_cell_type(3) == "code"
assert len(notebook.cells) == 5
notebook.edit_cell(index=1, content="cell1")
notebook.focus_cell(1)
notebook.current_cell.send_keys("a")
assert notebook.get_cell_contents(1) == ""
assert notebook.get_cell_contents(2) == "cell1"
notebook.edit_cell(index=1, content='cell1')
notebook.edit_cell(index=2, content='cell2')
notebook.edit_cell(index=3, content='cell3')
notebook.focus_cell(2)
notebook.current_cell.send_keys("b")
assert notebook.get_cell_contents(1) == "cell1"
assert notebook.get_cell_contents(2) == "cell2"
assert notebook.get_cell_contents(3) == ""
assert notebook.get_cell_contents(4) == "cell3"
# insert above multiple selected cells
notebook.focus_cell(1)
shift(notebook.browser, Keys.DOWN)
notebook.current_cell.send_keys('a')
# insert below multiple selected cells
notebook.focus_cell(2)
shift(notebook.browser, Keys.DOWN)
notebook.current_cell.send_keys('b')
assert notebook.get_cells_contents()[1:5] == ["", "cell1", "cell2", ""]

@ -131,10 +131,17 @@ class Notebook:
JS = 'return Jupyter.notebook.get_cells().map(function(c) {return c.get_text();})'
return self.browser.execute_script(JS)
def get_cell_contents(self, index=0, selector='div .CodeMirror-code'):
return self.cells[index].find_element_by_css_selector(selector).text
def set_cell_metadata(self, index, key, value):
JS = 'Jupyter.notebook.get_cell({}).metadata.{} = {}'.format(index, key, value)
return self.browser.execute_script(JS)
def get_cell_type(self, index=0):
JS = 'return Jupyter.notebook.get_cell({}).cell_type'.format(index)
return self.browser.execute_script(JS)
def set_cell_input_prompt(self, index, prmpt_val):
JS = 'Jupyter.notebook.get_cell({}).set_input_prompt({})'.format(index, prmpt_val)
self.browser.execute_script(JS)

@ -9,20 +9,27 @@ from notebook.config_manager import BaseJSONConfigManager
def test_json():
tmpdir = tempfile.mkdtemp()
try:
root_data = dict(a=1, x=2, nest={'a':1, 'x':2})
with open(os.path.join(tmpdir, 'foo.json'), 'w') as f:
json.dump(dict(a=1), f)
json.dump(root_data, f)
# also make a foo.d/ directory with multiple json files
os.makedirs(os.path.join(tmpdir, 'foo.d'))
with open(os.path.join(tmpdir, 'foo.d', 'a.json'), 'w') as f:
json.dump(dict(a=2, b=1), f)
json.dump(dict(a=2, b=1, nest={'a':2, 'b':1}), f)
with open(os.path.join(tmpdir, 'foo.d', 'b.json'), 'w') as f:
json.dump(dict(a=3, b=2, c=3), f)
json.dump(dict(a=3, b=2, c=3, nest={'a':3, 'b':2, 'c':3}, only_in_b={'x':1}), f)
manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=False)
data = manager.get('foo')
assert 'a' in data
assert 'x' in data
assert 'b' not in data
assert 'c' not in data
assert data['a'] == 1
assert 'x' in data['nest']
# if we write it out, it also shouldn't pick up the subdirectoy
manager.set('foo', data)
data = manager.get('foo')
assert data == root_data
manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=True)
data = manager.get('foo')
@ -33,6 +40,17 @@ def test_json():
assert data['a'] == 1
assert data['b'] == 2
assert data['c'] == 3
assert data['nest']['a'] == 1
assert data['nest']['b'] == 2
assert data['nest']['c'] == 3
assert data['nest']['x'] == 2
# when writing out, we don't want foo.d/*.json data to be included in the root foo.json
manager.set('foo', data)
manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=False)
data = manager.get('foo')
assert data == root_data
finally:
shutil.rmtree(tmpdir)

@ -79,6 +79,9 @@ for more information.
install_requires = [
'jinja2',
'tornado>=4',
# pyzmq>=17 is not technically necessary,
# but hopefully avoids incompatibilities with Tornado 5. April 2018
'pyzmq>=17',
'ipython_genutils',
'traitlets>=4.2.1',
'jupyter_core>=4.4.0',

Loading…
Cancel
Save