Compare commits

...

114 Commits
main ... 4.0.x

Author SHA1 Message Date
Thomas Kluyver 2530a940c9 Merge pull request #2042 from clarka34/patch-2
9 years ago
clarka34 85aedbf5c0 Update button icon.
9 years ago
Min RK d0c955388a back to dev
10 years ago
Min RK b55157282a release 4.0.6
10 years ago
Min RK 6efb1145da note changes in 4.0.6
10 years ago
Min RK 1c47294bcf catch errors in app_initialized callbacks
10 years ago
Min RK f5e3844787 use events.one for notebook first-load
10 years ago
Matthias Bussonnier de0360d7d9 Fix bad message break notebook
10 years ago
Matthias Bussonnier 729f9bb54e include mathjax extensions that are dynamically loaded
10 years ago
Matthias Bussonnier 131bdd55cf Fix overzealous auto escape
10 years ago
Min RK 0350c7f124 CVE-2015-7337 assigned
10 years ago
Min RK 3ccd254907 formatting for long_description
10 years ago
Min RK c9937f8b38 use more conservative rule to pull in setuptools
10 years ago
Min RK bf19b3cd0b 4.0.6.dev
10 years ago
Min RK ce8ccf168c note CVEs in 4.0.5
10 years ago
Min RK 9e63dd89b6 Merge edit-redirect fix into 4.0.x
10 years ago
Safia Abdalla 9ed5848e82 Added long_description to setup.py
11 years ago
Safia Abdalla b05293408a Added description text to setup.py
11 years ago
Min RK 1bec1b9808 Merge pull request #375 from Carreau/4.0.5
11 years ago
Matthias Bussonnier 0259d3df08 Update version number to 4.0.5
11 years ago
Matthias Bussonnier dd9876381f Fix XSS reported on Security list
11 years ago
Min RK 0600d6a5e6 4.0.4
11 years ago
Min RK caea335a73 install mathjax safe extension
11 years ago
Min RK 930415df3b release 4.0.3
11 years ago
Min RK d055356ebe install MathJax safe config
11 years ago
Min RK 3e2bde6472 release 4.0.2
11 years ago
Min RK c1c66c0021 note nbextension-install fix
11 years ago
Min RK 8080a798e0 relative import of ConfigManager
11 years ago
Min RK 42bea203dc add changelog
11 years ago
Min RK 8ef21fc474 enable MathJax safe mode
11 years ago
Thomas Kluyver d404af9d16 Use entry points for scripts
11 years ago
Min RK 68759c84d0 leave empty commit hash when none found
11 years ago
Min RK 4cb2b78828 Merge pull request #262 from takluyver/docs-4.x-misc
11 years ago
Matthias Bussonnier 735bd7ee36 Merge pull request #267 from minrk/mathjax-component
11 years ago
Min RK d2b3aa314d Merge pull request #266 from takluyver/multicell-selection
11 years ago
Min RK 4d4fed2e98 use mathjax component
11 years ago
Thomas Kluyver 0cde7269a5 JSdoc for merge_cells method
11 years ago
Thomas Kluyver eb5e82f295 Fix cell merge tests
11 years ago
Thomas Kluyver dcd676d499 Clear selected range on entering edit mode
11 years ago
Thomas Kluyver 92e266f4e2 Merge cells based on range selection
11 years ago
Thomas Kluyver 792f928578 Multi-cell selection based on a selection anchor cell
11 years ago
Thomas Kluyver 450597d754 First attempt at multi-cell selection
11 years ago
Thomas Kluyver 89c4defaf2 Miscellaneous doc updates and warning-squashing
11 years ago
Thomas Kluyver b9c88fdf84 Add browser compatibility info
11 years ago
Min RK 6992965967 Merge pull request #258 from ebenolson/completer-z-index
11 years ago
Thomas Kluyver 3bcce96dd8 Merge pull request #259 from minrk/cm-5.5
11 years ago
Min RK 482906e76d specify codemirror dependency more precisely
11 years ago
Eben Olson dde3c3cc75 increase completer z-index to be in front of pager
11 years ago
Min RK 6bd84b9df0 Merge pull request #251 from takluyver/i250
11 years ago
Thomas Kluyver 3a9493bcab Look for notebook config in nbconfig/ subdirectory
11 years ago
Min RK 2f3789fb95 back to dev
11 years ago
Min RK 1c839f686b release 4.0.1
11 years ago
Min RK 5b507019e6 release 4.0.0
11 years ago
Min RK 496289e441 Merge pull request #240 from takluyver/download-ipynb-ajax
11 years ago
Thomas Kluyver cf4341ac0d Merge pull request #242 from minrk/hardcode-widgets-js
11 years ago
Min RK 0afe9d2b1a Merge pull request #241 from takluyver/nbconvert-config-dir
11 years ago
Min RK ff191ae630 load widget extension in js
11 years ago
Min RK a36dcf2f98 export utils.load_extension
11 years ago
Thomas Kluyver 7e4354fbd9 Put config_dir in resources in nbconvert handlers
11 years ago
Thomas Kluyver 9c2fdb7c30 Use window.location trick for download as ipynb
11 years ago
Min RK 26334946f9 Merge pull request #238 from takluyver/Carreau-icons
11 years ago
Min RK 89124554f4 Merge pull request #237 from takluyver/forwport-8524
11 years ago
Thomas Kluyver e47a7e4fbe Merge pull request #236 from minrk/manifest
11 years ago
Thomas Kluyver 3bd961b492 Fix abstract checkpoint methods to match interface used
11 years ago
Min RK 42d4529703 Add missing files to manifest
11 years ago
Min RK 2218d7df95 Merge pull request #235 from takluyver/docs-mathjax
11 years ago
Min RK 4eda5e57ad Merge pull request #234 from takluyver/docs-extending-subdir
11 years ago
Thomas Kluyver 884ef1dc28 Fix up some issues with the Mathjax examples in the docs
11 years ago
Thomas Kluyver 72fa817fab Make 'extending' a directory in the docs
11 years ago
Thomas Kluyver 6ef2d6a995 Merge pull request #209 from ssanderson/contents-docs
11 years ago
Min RK 30c235def1 Merge pull request #216 from nitind/issue158_rendered_html_on_divs
11 years ago
Thomas Kluyver 2806cb2da8 Merge pull request #233 from minrk/install-no-js-css
11 years ago
Nitin Dahyabhai 4288dc1c6d Issue 158 - Rendered markdown div should get .rendered_html class
11 years ago
Min RK a394579b84 require js/css targets to exist
11 years ago
Scott Sanderson e76548a96a MAINT: Simpler way of writing classes.
11 years ago
Scott Sanderson 0d70a84ef1 DOC: More notes on Contents API.
11 years ago
Scott Sanderson 7e720ab22b WIP: Moar docs.
11 years ago
Scott Sanderson 9e13c3b0cd DOC: Initial work on Contents API docs.
11 years ago
Min RK 22aad2fcb7 Merge pull request #231 from takluyver/dev-docs
11 years ago
Thomas Kluyver 86ab103195 Remove docs on live-rebuilding CSS
11 years ago
Thomas Kluyver 96032f7ec1 Document installing the JS machinery
11 years ago
Min RK 788c16d1d5 Merge pull request #229 from takluyver/i223
11 years ago
Thomas Kluyver f2c5e6ba98 Catch error adding link to notebook list
11 years ago
Min RK c03a564655 Merge pull request #168 from takluyver/no-install-kernelspec
11 years ago
Thomas Kluyver 5ad3fd19f6 Don't install native kernelspec on startup
11 years ago
Thomas Kluyver 406a57d70d Merge pull request #228 from minrk/nbconvert-files
11 years ago
Min RK 854aa1af8e Merge pull request #222 from flying-sheep/patch-1
11 years ago
Min RK ca2a539617 Merge pull request #210 from takluyver/nbextension-enable-cmd
11 years ago
Min RK 5714cabb26 fix files redirect in nbconvert handlers
11 years ago
Thomas Kluyver f64dec096f Merge pull request #227 from minrk/rm-requirements
11 years ago
Min RK 2b5ba10ce9 remove requirements.txt
11 years ago
Min RK b0cae1f51b Merge pull request #214 from jasongrout/trait-instances
11 years ago
Min RK c0f3b0abed Merge pull request #120 from jdfreder/widgets
11 years ago
Philipp A. 3029212849 fixed logic error and moved question
11 years ago
Philipp A. e5ec203028 Ask for confirmation if kernel is busy
11 years ago
Thomas Kluyver 454a581830 Merge pull request #221 from minrk/swallow-gulp
11 years ago
Min RK c41df91b10 remove gulp
11 years ago
Jonathan Frederic fddd29f63a Use app_log
11 years ago
Thomas Kluyver ecdb1091d7 Merge pull request #220 from minrk/restart-kernel
11 years ago
Min RK 715e87afc2 Fix scope on restart buttons
11 years ago
Thomas Kluyver 0a93cc6c6a Merge pull request #219 from minrk/contents-docstring
11 years ago
Min RK db86515621 Merge pull request #218 from takluyver/term-server-dir-envvar
11 years ago
Min RK c42869c3b8 remove 'name' arg from file_exists docstring
11 years ago
Thomas Kluyver a425ed30ef Env variables for server root & URL in terminals
11 years ago
Jason Grout cf69ab7428 Use instances of traits instead of trait classes
11 years ago
Thomas Kluyver 00bb47fb24 Error on disabling extension not currently enabled
11 years ago
Thomas Kluyver 095e77dfd7 Error on >1 extension for enable/disable commands
11 years ago
Thomas Kluyver c21debfc4a Use notebook config file for nbextension commands
11 years ago
Thomas Kluyver ff9f36e7f0 Local imports of ConfigManager to avoid Py2 circular import issue
11 years ago
Thomas Kluyver 29fabd3c16 Add command-line interface to enable/disable nbextensions
11 years ago
Matthias Bussonnier 688dc2c6e8 iconset for Jupyter notebook
11 years ago
Jonathan Frederic 9a924963b1 Use correct log call.
11 years ago
Jonathan Frederic 01be52894d Add errback to JS init.
11 years ago
Jonathan Frederic 32fd103bad Hardcode references to the widgets.
11 years ago

@ -20,7 +20,7 @@ before_install:
- 'if [[ $GROUP == js* ]]; then npm install -g casperjs; fi'
- git clone --quiet --depth 1 https://github.com/minrk/travis-wheels travis-wheels
install:
- pip install -f travis-wheels/wheelhouse -r requirements.txt file://$PWD#egg=notebook[test] coveralls
- pip install -f travis-wheels/wheelhouse --pre file://$PWD#egg=notebook[test] coveralls
script:
- 'if [[ $GROUP == js* ]]; then python -m notebook.jstest ${GROUP:3}; fi'
- 'if [[ $GROUP == python ]]; then nosetests --with-coverage --cover-package=notebook notebook; fi'

@ -55,7 +55,7 @@ ADD . /srv/notebook
WORKDIR /srv/notebook/
RUN chmod -R +rX /srv/notebook
RUN pip3 install -r requirements.txt -e .[test]
RUN pip3 install -e .[test]
# install kernels
RUN python2 -m ipykernel.kernelspec

@ -1,8 +1,12 @@
include COPYING.md
include CONTRIBUTING.md
include README.md
include package.json
include bower.json
include .bowerrc
include setupbase.py
include Dockerfile
graft tools
# Documentation
graft docs

@ -4,10 +4,9 @@ The Jupyter HTML notebook is a web-based notebook environment for interactive co
Dev quickstart:
* Create a virtual env (ie jupyter-dev)
* ensure that you have node/npm installed (ie brew install node on OS X)
* ensure that you have node/npm installed (e.g. `brew install node` on OS X)
* Clone this repo and cd into it
* pip install -r requirements.txt -e .
* `pip install --pre -e .`
_NOTE_: For Debian/Ubuntu systems, if you're installing the system node you need
to use the 'nodejs-legacy' package and not the 'node' package.
@ -16,15 +15,15 @@ Launch with:
jupyter notebook
For Ubuntu Trusty:
Example installation (tested on Ubuntu Trusty):
```
sudo apt-get install nodejs-legacy npm python-virtualenv python-dev
python2 -m virtualenv ~/.virtualenvs/notebook
source ~/.virtualenvs/notebook/bin/activate
# ensure setuptools/pip are up-to-date
pip install --upgrade setuptools pip
git clone https://github.com/jupyter/notebook.git
cd notebook
pip install -r requirements.txt -e .
pip install --pre -e .
jupyter notebook
```

@ -5,14 +5,14 @@
"backbone": "components/backbone#~1.2",
"bootstrap": "components/bootstrap#~3.3",
"bootstrap-tour": "0.9.0",
"codemirror": ">=4.11",
"codemirror": "~5.5",
"es6-promise": "~1.0",
"font-awesome": "components/font-awesome#~4.2.0",
"google-caja": "5669",
"jquery": "components/jquery#~2.0",
"jquery-ui": "components/jqueryui#~1.10",
"marked": "~0.3",
"MathJax": "~2.5",
"MathJax": "components/MathJax#~2.5",
"moment": "~2.8.4",
"requirejs": "~2.1",
"term.js": "chjj/term.js#~0.0.4",

@ -0,0 +1,20 @@
# Add this into the info.plist file of an application
# and the icns icon in Contents/Resources
# then move the application twice :
# http://superuser.com/questions/178316/how-to-set-an-icon-for-a-file-type-on-mac
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>ipynb</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>ipynb_mac_icon</string>
<key>CFBundleTypeName</key>
<string>IPython notebook file</string>
<key>CFBundleTypeRole</key>
<string>None</string>
</dict>
<array>

@ -0,0 +1,16 @@
#!/bin/bash
INKSCAPE=inkscape
${INKSCAPE} -z -C --file=ipynb_icon_16x16.svg --export-png=ipynb_icon_16x16_uncrush.png
${INKSCAPE} -z -C --file=ipynb_icon_24x24.svg --export-png=ipynb_icon_24x24_uncrush.png
${INKSCAPE} -z -C --file=ipynb_icon_32x32.svg --export-png=ipynb_icon_32x32_uncrush.png
${INKSCAPE} -z -C --file=ipynb_icon_512x512.svg --export-png=ipynb_icon_64x64_uncrush.png -w 64 -h 64
${INKSCAPE} -z -C --file=ipynb_icon_512x512.svg --export-png=ipynb_icon_128x128_uncrush.png -w 128 -h 128
${INKSCAPE} -z -C --file=ipynb_icon_512x512.svg --export-png=ipynb_icon_256x256_uncrush.png -w 256 -h 256
${INKSCAPE} -z -C --file=ipynb_icon_512x512.svg --export-png=ipynb_icon_512x512_uncrush.png -w 512 -h 512
for file in `ls *_uncrush.png`; do
pngcrush -brute -l 9 -reduce -rem alla -rem text -rem time -rem gAMA -rem cHRM -rem iCCP -rem sRGB $file `basename $file _uncrush.png`.png
rm $file
done

@ -0,0 +1,149 @@
<?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"
version="1.0"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="ipynb_icon_16x16.svg"
width="16"
height="16"
inkscape:export-filename="/Users/bussonniermatthias/dev/ipython/docs/resources/ipynb_icon_16x16.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<metadata
id="metadata371">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
inkscape:window-height="755"
inkscape:window-width="1343"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:zoom="32.924658"
inkscape:cx="4.028552"
inkscape:cy="6.0286893"
inkscape:window-x="67"
inkscape:window-y="65"
inkscape:current-layer="text4040"
width="210mm"
height="40mm"
units="px"
showgrid="true"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid3926"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<defs
id="defs4">
<linearGradient
id="linearGradient4689">
<stop
id="stop4157"
offset="0"
style="stop-color:#5a9fd4;stop-opacity:1;" />
<stop
id="stop4159"
offset="1"
style="stop-color:#306998;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4161">
<stop
style="stop-color:#fab434;stop-opacity:1"
offset="0"
id="stop4691" />
<stop
style="stop-color:#fb9143;stop-opacity:1"
offset="1"
id="stop4693" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4161"
id="linearGradient3941"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.07938588,0,0,0.07938588,-5.0860229,1.6938337)"
x1="116.74316"
y1="62.91114"
x2="190.06432"
y2="149.74373" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4161"
id="linearGradient3943"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.06968992,0,0,0.06968992,-2.9157072,3.1465468)"
x1="116.74316"
y1="62.91114"
x2="190.06432"
y2="149.74373" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689"
id="linearGradient3945"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.06968992,0,0,0.06968992,-2.9157072,3.1465468)"
x1="116.74316"
y1="62.91114"
x2="190.06432"
y2="149.74373" />
</defs>
<path
style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 2,15 2,1 11,1 14,4 14,15 2,15"
id="path3956"
inkscape:connector-curvature="0" />
<path
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#7d7d7d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99363834;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
d="m 1,0 0,16 14,0 0.03125,-12.4375 -3.6875,-3.53125 z m 9,1 0,4 4,0 0,10 L 2,15 2,1 z m 1,0 3,3 -3,0 z"
id="path4338"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccc" />
<g
style="font-size:9.22902393px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3945);fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
id="text4040"
transform="translate(0,-1)">
<path
d="M 6.3936117,14 4,7.4375 4,14 3,14 3,6 4.4316382,6 7,13 7,6 8,6 8,14"
style="fill:url(#linearGradient3943);font-family:Droid Sans;-inkscape-font-specification:Droid Sans;fill-opacity:1.0"
id="path3937"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<path
d="m 11.611865,8.3182664 c 0.321685,5.7e-6 0.614285,0.061605 0.8778,0.1847998 0.263506,0.1232054 0.487661,0.3080051 0.672466,0.5543996 0.188217,0.2429824 0.333661,0.5458484 0.436333,0.9085998 0.102658,0.3627584 0.153994,0.7836904 0.154,1.2627984 -6e-6,0.482536 -0.05134,0.90689 -0.154,1.273066 -0.10267,0.362757 -0.248116,0.667334 -0.436333,0.913732 -0.184805,0.246401 -0.40896,0.432912 -0.672466,0.559533 -0.263515,0.1232 -0.556115,0.1848 -0.8778,0.1848 -0.201914,0 -0.385003,-0.02225 -0.549265,-0.06673 -0.16427,-0.04449 -0.313137,-0.10267 -0.446601,-0.174534 -0.130046,-0.07528 -0.246402,-0.162555 -0.349066,-0.2618 -0.09924,-0.09924 -0.188224,-0.203622 -0.2669332,-0.313133 L 10,13.454283 10,14 9,14 9,6 l 1,0 -4e-6,3.1601324 c 0.078718,-0.1197727 0.167691,-0.2309947 0.266937,-0.3336664 0.09924,-0.1026607 0.213887,-0.1916389 0.343933,-0.2669332 0.133464,-0.075283 0.28233,-0.1334609 0.4466,-0.1745332 0.164263,-0.044483 0.349063,-0.066728 0.554399,-0.066734 M 11.4322,9.0933982 c -0.273781,5.1e-6 -0.50307,0.044493 -0.687868,0.1334667 -0.181379,0.08556 -0.328535,0.2173155 -0.441466,0.3952668 -0.109516,0.1779595 -0.188223,0.4004033 -0.236133,0.6673323 -0.04449,0.266937 -0.06673,0.58007 -0.06673,0.9394 -10e-7,0.345646 0.02225,0.653646 0.06673,0.923999 0.04791,0.266935 0.12662,0.4928 0.236133,0.677599 0.112933,0.181379 0.261798,0.319979 0.446601,0.4158 0.184796,0.09239 0.415796,0.138601 0.692998,0.1386 0.461996,10e-7 0.800796,-0.18651 1.016399,-0.559533 0.219019,-0.37302 0.328529,-0.908597 0.328534,-1.606732 -5e-6,-0.711818 -0.109516,-1.2439729 -0.328534,-1.5964653 C 12.243261,9.2696478 11.901039,9.0934037 11.4322,9.0933986"
style="fill:url(#linearGradient3941);font-family:Droid Sans;-inkscape-font-specification:Droid Sans;fill-opacity:1.0"
id="path3939"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccsccccccccccccccccccscccscccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.0 KiB

@ -0,0 +1,167 @@
<?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"
version="1.0"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="ipynb_icon_24x24.svg"
width="24"
height="24"
inkscape:export-filename="/Users/bussonniermatthias/dev/ipython/docs/resources/ipynb_icon_24x24.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<metadata
id="metadata371">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
inkscape:window-height="677"
inkscape:window-width="1280"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#d9d9d9"
id="base"
inkscape:zoom="22.627417"
inkscape:cx="14.369924"
inkscape:cy="14.833103"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:current-layer="svg2"
width="210mm"
height="40mm"
units="px"
showgrid="true"
inkscape:window-maximized="0"
inkscape:snap-grids="true"
inkscape:snap-global="true"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid3926"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<defs
id="defs4">
<linearGradient
id="linearGradient4167">
<stop
id="stop4169"
offset="0"
style="stop-color:#fab434;stop-opacity:1" />
<stop
id="stop4171"
offset="1"
style="stop-color:#fb9143;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient4689-7">
<stop
style="stop-color:#5a9fd4;stop-opacity:1;"
offset="0"
id="stop4691-6" />
<stop
style="stop-color:#306998;stop-opacity:1;"
offset="1"
id="stop4693-4" />
</linearGradient>
<linearGradient
id="linearGradient4689-3">
<stop
style="stop-color:#5a9fd4;stop-opacity:1;"
offset="0"
id="stop4691-8" />
<stop
style="stop-color:#306998;stop-opacity:1;"
offset="1"
id="stop4693-0" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4167"
id="linearGradient3382"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.10331077,0,0,0.10331077,-4.3899917,5.891698)"
x1="116.74316"
y1="62.91114"
x2="190.06432"
y2="149.74373" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4167"
id="linearGradient3385"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.0933059,0,0,0.0933059,-2.6120135,7.4686107)"
x1="116.74316"
y1="62.91114"
x2="190.06432"
y2="149.74373" />
</defs>
<path
style="fill:#ffffff;stroke:none"
d="M 3,23 3,1 19,1 22,4 22,23 3,23"
id="path3956"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#7d7d7d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99363834;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
d="M 2,0 2,24 23,24 23.03125,3.5625 19.34375,0.03125 2,0 z m 16,1 0,4 4,0 0,18 L 3,23 3,1 18,1 z m 1,0 3,3 -3,0 0,-3 z"
id="path4338"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccc" />
<path
style="fill:#4d4d4d;fill-opacity:1;fill-rule:evenodd"
d="m 9.0631018,3.9984663 0,3.9686017 -1.0252408,0 0.00592,-1.0012742 -1.0164801,-0.010113 0,2.0113872 3.0000001,0 0,-4.9686017 z"
id="_92110424"
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0" />
<path
d="m 11.019015,6.0000004 0,4.9999996 1,0 0,-2 2,0 0,-2.9999996 -3,0 z m 1,1 1,0 0,1 -1,0 0,-1 z"
class="fil1"
id="_92100232"
inkscape:connector-curvature="0"
style="fill:#4d4d4d;fill-opacity:1;fill-rule:evenodd"
sodipodi:nodetypes="cccccccccccc" />
<path
sodipodi:nodetypes="cccccccccccc"
id="path3329"
style="font-size:12.35648537px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3385);fill-opacity:1.0;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
d="m 5.969491,13 0.9967434,0.990704 4.0032566,6.537137 0,-7.527841 L 12,12.9921 12,22.000026 10.969491,22 9.9775096,21.079451 5.969491,14.435247 l 0,7.564753 -1,0 0,-9" />
<path
sodipodi:nodetypes="csssssssccssssssscccccc"
id="path3331"
style="font-size:12.35648537px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3382);fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
d="m 19.387284,18.246903 c -7e-6,-0.904074 -0.187059,-1.612194 -0.561153,-2.124362 -0.369654,-0.51661 -0.879589,-0.774918 -1.529808,-0.774925 -0.650228,7e-6 -1.162391,0.258315 -1.536489,0.774925 -0.369651,0.512168 -0.554474,1.220288 -0.554472,2.124362 -2e-6,0.904082 0.184821,1.614428 0.554472,2.131043 0.374098,0.512164 0.886261,0.768246 1.536489,0.768244 0.650219,2e-6 1.160154,-0.25608 1.529808,-0.768244 0.374094,-0.516615 0.561146,-1.226961 0.561153,-2.131043 M 14.969491,16 c 0.258306,-0.578575 0.819288,-1.140045 1.211207,-1.353824 0.396366,-0.218219 0.868446,-0.327332 1.416242,-0.32734 0.908526,8e-6 1.645595,0.360749 2.211207,1.082222 0.570052,0.721488 0.855082,1.670102 0.85509,2.845845 -8e-6,1.175751 -0.285038,2.124364 -0.85509,2.845844 -0.565612,0.721482 -1.302681,1.082223 -2.211207,1.082223 -0.547796,0 -1.019876,-0.106881 -1.416242,-0.320658 C 15.788779,21.636086 15.227797,21.44536 14.969491,21 l 0,1 -1,0 0,-10 1,0 0,3" />
<path
style="fill:#4d4d4d;fill-opacity:1;fill-rule:evenodd"
d="m 15.016466,5.983534 0,2.0072866 0,0.9927134 1,0 1,0 0,1 -2,0 0,1 1,0 1,0 1,0 0,-1 0,-1 0,-1 0,-1 0,-1 -1,0 0,2 -1,0 0,-2 -1,0 z m 2,5 0,0 z"
id="path3433"
sodipodi:nodetypes="ccccccccccccccccccccccc"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

@ -0,0 +1,311 @@
<?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"
version="1.0"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="icon_32x32.svg"
width="32"
height="32"
inkscape:export-filename="/Users/bussonniermatthias/dev/ipython/docs/resources/ipynb_icon_32x32@2x.png"
inkscape:export-xdpi="180"
inkscape:export-ydpi="180">
<metadata
id="metadata371">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
inkscape:window-height="677"
inkscape:window-width="1280"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:zoom="16"
inkscape:cx="1.844338"
inkscape:cy="15.013138"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:current-layer="svg2"
width="210mm"
height="40mm"
units="mm"
showgrid="true"
inkscape:window-maximized="0"
inkscape:snap-global="false">
<inkscape:grid
type="xygrid"
id="grid2928"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<defs
id="defs4">
<linearGradient
id="linearGradient4689">
<stop
style="stop-color:#5a9fd4;stop-opacity:1;"
offset="0"
id="stop4691" />
<stop
style="stop-color:#306998;stop-opacity:1;"
offset="1"
id="stop4693" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689"
id="linearGradient4355"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.94210934,0,0,0.94210934,1.2341389,2.7751101)"
x1="12.796725"
y1="13.227233"
x2="27.51895"
y2="31.016586" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689"
id="linearGradient4357"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.94210934,0,0,0.94210934,1.2341389,2.7751101)"
x1="12.796725"
y1="13.227233"
x2="27.51895"
y2="31.016586" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689"
id="linearGradient3720"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.04569196,0,0,0.04569196,1.6101549,-10.796096)"
x1="187.33029"
y1="618.22144"
x2="393.25586"
y2="867.04816" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3266"
gradientUnits="userSpaceOnUse"
x1="323.06018"
y1="147.10051"
x2="147.68851"
y2="293.00339" />
<linearGradient
id="linearGradient4689-6">
<stop
style="stop-color:#5a9fd4;stop-opacity:1"
offset="0"
id="stop4691-3" />
<stop
style="stop-color:#306998;stop-opacity:1"
offset="1"
id="stop4693-8" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3256"
gradientUnits="userSpaceOnUse"
x1="486.50031"
y1="184.54053"
x2="496.16876"
y2="248.36336" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3254"
gradientUnits="userSpaceOnUse"
x1="486.50031"
y1="184.54053"
x2="496.16876"
y2="248.36336" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3260"
gradientUnits="userSpaceOnUse"
x1="485.7803"
y1="185.98055"
x2="496.88876"
y2="249.08336" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3258"
gradientUnits="userSpaceOnUse"
x1="485.7803"
y1="185.98055"
x2="496.88876"
y2="249.08336" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3264"
gradientUnits="userSpaceOnUse"
x1="484.3403"
y1="182.38054"
x2="495.44876"
y2="243.32335" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3262"
gradientUnits="userSpaceOnUse"
x1="484.3403"
y1="182.38054"
x2="495.44876"
y2="243.32335" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3174"
gradientUnits="userSpaceOnUse"
x1="486.50031"
y1="184.54053"
x2="496.16876"
y2="248.36336" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3176"
gradientUnits="userSpaceOnUse"
x1="486.50031"
y1="184.54053"
x2="496.16876"
y2="248.36336" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3178"
gradientUnits="userSpaceOnUse"
x1="485.7803"
y1="185.98055"
x2="496.88876"
y2="249.08336" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3180"
gradientUnits="userSpaceOnUse"
x1="485.7803"
y1="185.98055"
x2="496.88876"
y2="249.08336" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3182"
gradientUnits="userSpaceOnUse"
x1="484.3403"
y1="182.38054"
x2="495.44876"
y2="243.32335" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3184"
gradientUnits="userSpaceOnUse"
x1="484.3403"
y1="182.38054"
x2="495.44876"
y2="243.32335" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4689-6"
id="linearGradient3186"
gradientUnits="userSpaceOnUse"
x1="323.06018"
y1="147.10051"
x2="147.68851"
y2="293.00339" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4328"
id="linearGradient3314"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.14130513,0,0,0.14130513,-7.8428899,8.0251755)"
x1="116.74316"
y1="62.91114"
x2="190.06432"
y2="149.74373" />
<linearGradient
id="linearGradient4328">
<stop
id="stop4330"
offset="0"
style="stop-color:#fab434;stop-opacity:1" />
<stop
id="stop4332"
offset="1"
style="stop-color:#fb9143;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4328"
id="linearGradient3316"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.14130513,0,0,0.14130513,-5.8855851,8.0251755)"
x1="116.74316"
y1="62.91114"
x2="190.06432"
y2="149.74373" />
</defs>
<path
style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 4,31 4,1 21.957779,1.0144872 28,7 28,31 4,31 z"
id="path2939"
sodipodi:nodetypes="cccccc" />
<path
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#7d7d7d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99363834;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
d="M 3,0 3,32 29,32 29,6.5881566 22.494212,0 3,0 z m 18,1 0,7 7,0 0,23 L 4,31 4,1 21,1 z m 1,0 6,6 -6,0 0,-6 z"
id="path4338-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccc" />
<path
inkscape:connector-curvature="0"
id="path3277"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:267.69692993px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3316);fill-opacity:1;stroke:#000000;stroke-width:0.08421666;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 5.9182142,16.390066 2.4853226,0 6.0488362,11.412381 0,-11.412381 1.790894,0 0,13.641861 -2.485322,0 -6.0488362,-11.412381 0,11.412381 -1.7908946,0 0,-13.641861" />
<path
inkscape:connector-curvature="0"
id="path3279"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:267.69692993px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3314);fill-opacity:1;stroke:#000000;stroke-width:0.08421666;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 25.232346,24.924225 c -9e-6,-1.236564 -0.255851,-2.205107 -0.767526,-2.905635 -0.505601,-0.706602 -1.203074,-1.059908 -2.092423,-1.059917 -0.889361,9e-6 -1.589879,0.353315 -2.101559,1.059917 -0.505597,0.700528 -0.758392,1.669071 -0.758389,2.905635 -3e-6,1.236573 0.252792,2.208163 0.758389,2.914771 0.51168,0.700521 1.212198,1.050781 2.101559,1.05078 0.889349,10e-7 1.586822,-0.350259 2.092423,-1.05078 0.511675,-0.706608 0.767517,-1.678198 0.767526,-2.914771 m -5.719897,-3.572652 c 0.353302,-0.609138 0.797979,-1.059907 1.334033,-1.352307 0.542137,-0.298472 1.187833,-0.447713 1.93709,-0.447724 1.242653,1.1e-5 2.250792,0.49342 3.024418,1.480229 0.779699,0.986827 1.169553,2.284311 1.169564,3.892454 -1.1e-5,1.608153 -0.389865,2.905636 -1.169564,3.892453 -0.773626,0.98682 -1.781765,1.480229 -3.024418,1.480229 -0.749257,0 -1.394953,-0.146195 -1.93709,-0.438586 -0.536054,-0.298482 -0.980731,-0.752296 -1.334033,-1.361445 l 0,1.535051 -1.690385,0 0,-14.217506 1.690385,0 0,5.537152" />
<text
sodipodi:linespacing="125%"
id="text4334"
y="13.263572"
x="5.858809"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.92461967px;line-height:125%;font-family:'Myriad Pro';-inkscape-font-specification:'Myriad Pro';letter-spacing:0px;word-spacing:0px;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="13.263572"
x="5.858809"
id="tspan4336"
sodipodi:role="line">Jupyter</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

@ -0,0 +1,226 @@
<?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"
version="1.0"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="icon_512x512.svg"
width="512"
height="512"
inkscape:export-filename="/Users/bussonniermatthias/dev/ipython/docs/resources/icon_1024x1024.png"
inkscape:export-xdpi="180"
inkscape:export-ydpi="180">
<metadata
id="metadata371">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
inkscape:window-height="855"
inkscape:window-width="1440"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:zoom="1.0730821"
inkscape:cx="-301.17043"
inkscape:cy="112.5086"
inkscape:window-x="-7"
inkscape:window-y="6"
inkscape:current-layer="svg2"
width="210mm"
height="40mm"
units="mm"
showgrid="false"
inkscape:window-maximized="0"
inkscape:snap-global="false">
<inkscape:grid
type="xygrid"
id="grid2928"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<defs
id="defs4">
<linearGradient
id="linearGradient4328">
<stop
id="stop4330"
offset="0"
style="stop-color:#fab434;stop-opacity:1" />
<stop
id="stop4332"
offset="1"
style="stop-color:#fb9143;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient3919">
<stop
style="stop-color:#e4e4e4;stop-opacity:1;"
offset="0"
id="stop3921" />
<stop
id="stop3927"
offset="1"
style="stop-color:#ffffff;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4689">
<stop
style="stop-color:#5a9fd4;stop-opacity:1;"
offset="0"
id="stop4691" />
<stop
style="stop-color:#306998;stop-opacity:1;"
offset="1"
id="stop4693" />
</linearGradient>
<filter
inkscape:collect="always"
id="filter3871"
color-interpolation-filters="sRGB">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="2.9338986"
id="feGaussianBlur3873" />
</filter>
<filter
inkscape:collect="always"
id="filter3913"
color-interpolation-filters="sRGB">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.75310748"
id="feGaussianBlur3915" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3919"
id="linearGradient3925"
x1="209.00497"
y1="-22.631527"
x2="200.9668"
y2="-2.0393581"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.2092365,0,0,2.2092365,-68.579768,91.189025)" />
<linearGradient
id="linearGradient4689-6">
<stop
style="stop-color:#5a9fd4;stop-opacity:1"
offset="0"
id="stop4691-3" />
<stop
style="stop-color:#306998;stop-opacity:1"
offset="1"
id="stop4693-8" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4328"
id="linearGradient3314"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.181239,0,0,2.181239,-111.61182,113.06547)"
x1="116.74316"
y1="62.91114"
x2="190.06432"
y2="149.74373" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4328"
id="linearGradient3316"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.181239,0,0,2.181239,-81.398128,113.06547)"
x1="116.74316"
y1="62.91114"
x2="190.06432"
y2="149.74373" />
</defs>
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/Users/matthiasbussonnier/Desktop/ipython-python.png"
style="fill:#666666;fill-opacity:0.99033813;stroke:#7d7d7d;stroke-width:1.08476496;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter3871)"
d="m 20,279.27442 88.35063,0 c 33.9881,0 77.49135,12.81451 77.49135,29.1526 L 185.84198,492 20,492 Z"
id="path3077"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc"
transform="matrix(2.2092365,0,0,2.2092365,35.81527,-594.94434)" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4338"
d="m 79.999519,21.999517 194.983301,0 c 61.89823,0 171.01766,39.636924 171.01766,64.410449 l 0,405.590514 -366.000961,0 z"
style="fill:#ffffff;fill-opacity:0.99033813;stroke:#7d7d7d;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
inkscape:export-filename="/Users/matthiasbussonnier/Desktop/ipython-python.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path3875"
d="m 172.44062,-29.205599 c 12.43851,5.333061 24.39875,11.169395 29.07043,28.60434895 8.5133,-4.59641195 30.96516,-11.88953595 31.36664,-1.19791745"
style="fill:#ffffff;stroke:#7d7d7d;stroke-width:1.08476496;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3913)"
transform="matrix(2.2092365,0,0,2.2092365,-68.579768,91.189025)" />
<path
style="fill:url(#linearGradient3925);fill-opacity:1;stroke:#7d7d7d;stroke-width:2;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 274.98635,21.999991 c 32.90208,0 87.16499,12.824171 101.61943,66.768899 18.80789,-10.154561 68.40936,-26.266797 69.29632,-2.646483 0,-40.095253 -127.94367,-64.122416 -170.91575,-64.122416 z"
id="path4384"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
inkscape:connector-curvature="0"
id="path3277"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:267.69692993px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3316);fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:1.3;stroke-miterlimit:4;stroke-dasharray:none"
d="m 100.80974,242.18906 38.36437,0 93.3721,176.16579 0,-176.16579 27.64492,0 0,210.58088 -38.36437,0 -93.3721,-176.16579 0,176.16579 -27.64492,0 0,-210.58088" />
<path
inkscape:connector-curvature="0"
id="path3279"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:267.69692993px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3314);fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:1.3;stroke-miterlimit:4;stroke-dasharray:none"
d="m 398.94991,373.92553 c -1.4e-4,-19.08806 -3.94941,-34.03886 -11.84782,-44.85247 -7.80464,-10.90738 -18.57109,-16.36113 -32.29942,-16.36127 -13.7285,1.4e-4 -24.54197,5.45389 -32.44045,16.36127 -7.80458,10.81361 -11.70683,25.76441 -11.70677,44.85247 -6e-5,19.08821 3.90219,34.08603 11.70677,44.9935 7.89848,10.81351 18.71195,16.22025 32.44045,16.22023 13.72833,2e-5 24.49478,-5.40672 32.29942,-16.22023 7.89841,-10.90747 11.84768,-25.90529 11.84782,-44.9935 m -88.29446,-55.14879 c 5.4537,-9.40288 12.3179,-16.36112 20.59263,-20.87472 8.36862,-4.60733 18.33583,-6.91107 29.90165,-6.91123 19.18205,1.6e-4 34.74406,7.61661 46.68605,22.84936 12.03572,15.23304 18.05365,35.26148 18.05382,60.08538 -1.7e-4,24.82405 -6.0181,44.85249 -18.05382,60.08537 -11.94199,15.23291 -27.504,22.84936 -46.68605,22.84936 -11.56582,0 -21.53303,-2.25672 -29.90165,-6.77017 -8.27473,-4.60748 -15.13893,-11.61273 -20.59263,-21.01578 l 0,23.69563 -26.09342,0 0,-219.46675 26.09342,0 0,85.47355" />
<text
sodipodi:linespacing="125%"
id="text4334"
y="164.01935"
x="99.892746"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:106.89102173px;line-height:125%;font-family:'Myriad Pro';-inkscape-font-specification:'Myriad Pro';letter-spacing:0px;word-spacing:0px;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
xml:space="preserve"><tspan
y="164.01935"
x="99.892746"
id="tspan4336"
sodipodi:role="line">Jupyter</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-919.78046"
y="540.88873"
id="text4228"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4230"
x="-919.78046"
y="540.88873" /></text>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 770 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

@ -0,0 +1,46 @@
.. _changelog:
Jupyter notebook changelog
==========================
A summary of changes in the Jupyter notebook.
For more detailed information, see `GitHub <https://github.com/jupyter/notebook>`__.
4.0.x
-----
4.0.6
*****
- fix installation of mathjax support files
- fix some double-escape regressions in 4.0.5
- fix a couple of cases where errors could prevent opening a notebook
4.0.5
*****
Security fixes for maliciously crafted files.
- `CVE-2015-6938 <http://www.openwall.com/lists/oss-security/2015/09/02/3>`__: malicious filenames
- `CVE-2015-7337 <http://www.openwall.com/lists/oss-security/2015/09/16/3>`__: malicious binary files in text editor.
Thanks to Jonathan Kamens at Quantopian and Juan Broullón for the reports.
4.0.4
*****
- Fix inclusion of mathjax-safe extension
4.0.2
*****
- Fix launching the notebook on Windows
- Fix the path searched for frontend config
- Fix nbextension-install on Python 2
4.0.0
*****
First release of the notebook as a standalone package.

@ -41,6 +41,9 @@ extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.autosummary',
'sphinx.ext.mathjax',
'IPython.sphinxext.ipython_console_highlighting',
]
# Add any paths that contain templates here, relative to this directory.
@ -120,7 +123,7 @@ todo_include_todos = False
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
# html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the

@ -3,30 +3,23 @@
Development
===========
Installing Javascript machinery
-------------------------------
CSS live reloading
------------------
Running the Notebook from the source code on Github requires some Javascript
tools to build/minify the CSS and Javascript components. We do these steps when
making releases, so there's no need for these tools when installing released
versions of the Notebook.
If you are working on notebook styling, you can use the live-reloading option
of gulp to watch for changes in the `.less` files and automatically rebuild the
`css` and reload the current page.
First, install `Node.js <https://nodejs.org/>`_. The installers on the
Node.js website also include Node's package manager, *npm*. Alternatively,
install both of these from your package manager. For example, on Ubuntu or Debian::
To do so we rely on the livereaload extension of various browser (`for chrome
<https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei>`_),
and the gulp-livereload extension.
To use the livereload extension, in the root of `notebook` project launch::
$ gulp watch
Any changes to any of the less files under the `notebook/static`
directory will trigger a rebuild of css and ask the reload extension to reload
the current page.
Do not forget to activate the extension for the current page by clicking on it.
The dot at the center of the extension icon will be come darker when the extension is activated.
sudo apt-get install nodejs-legacy npm
You can then build the Javascript and CSS by running::
python setup.py css js
This will automatically fetch the remaining dependencies (bower, less) and
install them in a subdirectory.

@ -13,11 +13,10 @@
"source": [
"# Motivating Examples\n",
"\n",
"---\n",
"\n",
"## The Lorenz Equations\n",
"### Source\n",
"```\\begin{align}\n",
"```\n",
"\\begin{align}\n",
"\\dot{x} & = \\sigma(y-x) \\\\\n",
"\\dot{y} & = \\rho x - y - xz \\\\\n",
"\\dot{z} & = -\\beta z + xy\n",
@ -37,7 +36,8 @@
"source": [
"## The Cauchy-Schwarz Inequality\n",
"### Source\n",
"```\\begin{equation*}\n",
"```\n",
"\\begin{equation*}\n",
"\\left( \\sum_{k=1}^n a_k b_k \\right)^2 \\leq \\left( \\sum_{k=1}^n a_k^2 \\right) \\left( \\sum_{k=1}^n b_k^2 \\right)\n",
"\\end{equation*}\n",
"```\n",
@ -53,7 +53,8 @@
"source": [
"## A Cross Product Formula\n",
"### Source\n",
"```\\begin{equation*}\n",
"```\n",
"\\begin{equation*}\n",
"\\mathbf{V}_1 \\times \\mathbf{V}_2 = \\begin{vmatrix}\n",
"\\mathbf{i} & \\mathbf{j} & \\mathbf{k} \\\\\n",
"\\frac{\\partial X}{\\partial u} & \\frac{\\partial Y}{\\partial u} & 0 \\\\\n",
@ -77,7 +78,8 @@
"source": [
"## The probability of getting \\(k\\) heads when flipping \\(n\\) coins is\n",
"### Source\n",
"```\\begin{equation*}\n",
"```\n",
"\\begin{equation*}\n",
"P(E) = {n \\choose k} p^k (1-p)^{ n-k} \n",
"\\end{equation*}\n",
"```\n",
@ -93,7 +95,8 @@
"source": [
"## An Identity of Ramanujan\n",
"### Source\n",
"```\\begin{equation*}\n",
"```\n",
"\\begin{equation*}\n",
"\\frac{1}{\\Bigl(\\sqrt{\\phi \\sqrt{5}}-\\phi\\Bigr) e^{\\frac25 \\pi}} =\n",
"1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}}\n",
"{1+\\frac{e^{-8\\pi}} {1+\\ldots} } } } \n",
@ -113,7 +116,8 @@
"source": [
"## A Rogers-Ramanujan Identity\n",
"### Source\n",
"```\\begin{equation*}\n",
"```\n",
"\\begin{equation*}\n",
"1 + \\frac{q^2}{(1-q)}+\\frac{q^6}{(1-q)(1-q^2)}+\\cdots =\n",
"\\prod_{j=0}^{\\infty}\\frac{1}{(1-q^{5j+2})(1-q^{5j+3})},\n",
"\\quad\\quad \\text{for $|q|<1$}. \n",
@ -133,7 +137,8 @@
"source": [
"## Maxwell's Equations\n",
"### Source\n",
"```\\begin{align}\n",
"```\n",
"\\begin{align}\n",
"\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} & = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\ \\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\\n",
"\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\\n",
"\\nabla \\cdot \\vec{\\mathbf{B}} & = 0 \n",
@ -153,8 +158,6 @@
"source": [
"# Equation Numbering and References\n",
"\n",
"---\n",
"\n",
"Equation numbering and referencing will be available in a future version of the Jupyter notebook."
]
},
@ -162,17 +165,17 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Inline Typesetting (Mixing Markdown and TeX)\n",
"\n",
"---\n",
"## Inline Typesetting (Mixing Markdown and TeX)\n",
"\n",
"While display equations look good for a page of samples, the ability to mix math and *formatted* **text** in a paragraph is also important.\n",
"\n",
"## Source\n",
"``` This expression $\\sqrt{3x-1}+(1+x)^2$ is an example of a TeX inline equation in a **[Markdown-formatted](http://daringfireball.net/projects/markdown/)** sentence. \n",
"### Source\n",
"```\n",
"This expression $\\sqrt{3x-1}+(1+x)^2$ is an example of a TeX inline equation in a [Markdown-formatted](http://daringfireball.net/projects/markdown/) sentence. \n",
"```\n",
"## Display\n",
"This expression $\\sqrt{3x-1}+(1+x)^2$ is an example of a TeX inline equation in a **[Markdown-formatted](http://daringfireball.net/projects/markdown/)** sentence. "
"\n",
"### Display\n",
"This expression $\\sqrt{3x-1}+(1+x)^2$ is an example of a TeX inline equation in a [Markdown-formatted](http://daringfireball.net/projects/markdown/) sentence. "
]
},
{
@ -181,8 +184,6 @@
"source": [
"# Other Syntax\n",
"\n",
"---\n",
"\n",
"You will notice in other places on the web that `$$` are needed explicitly to begin and end MathJax typesetting. This is **not** required if you will be using TeX environments, but the Jupyter notebook will accept this syntax on legacy notebooks. \n",
"\n",
"### Source\n",

@ -12,16 +12,22 @@ below, as well as the Markdown+TeX source.
Motivating Examples
===================
--------------
The Lorenz Equations
--------------------
Source
~~~~~~
``\begin{align} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{align}``
### Display
::
\begin{align}
\dot{x} & = \sigma(y-x) \\
\dot{y} & = \rho x - y - xz \\
\dot{z} & = -\beta z + xy
\end{align}
Display
~~~~~~~
.. raw:: latex
@ -32,13 +38,19 @@ Source
\end{align}
The Cauchy-Schwarz Inequality
-----------------------------
=============================
Source
~~~~~~
------
::
``\begin{equation*} \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) \end{equation*}``
### Display
\begin{equation*}
\left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)
\end{equation*}
Display
-------
.. raw:: latex
@ -47,13 +59,23 @@ Source
\end{equation*}
A Cross Product Formula
-----------------------
=======================
Source
~~~~~~
------
``\begin{equation*} \mathbf{V}_1 \times \mathbf{V}_2 = \begin{vmatrix} \mathbf{i} & \mathbf{j} & \mathbf{k} \\ \frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \\ \frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v} & 0 \end{vmatrix} \end{equation*}``
### Display
::
\begin{equation*}
\mathbf{V}_1 \times \mathbf{V}_2 = \begin{vmatrix}
\mathbf{i} & \mathbf{j} & \mathbf{k} \\
\frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \\
\frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v} & 0
\end{vmatrix}
\end{equation*}
Display
-------
.. raw:: latex
@ -66,13 +88,19 @@ Source
\end{equation*}
The probability of getting (k) heads when flipping (n) coins is
---------------------------------------------------------------
===============================================================
Source
~~~~~~
------
``\begin{equation*} P(E) = {n \choose k} p^k (1-p)^{ n-k} \end{equation*}``
### Display
::
\begin{equation*}
P(E) = {n \choose k} p^k (1-p)^{ n-k}
\end{equation*}
Display
-------
.. raw:: latex
@ -81,13 +109,21 @@ Source
\end{equation*}
An Identity of Ramanujan
------------------------
========================
Source
~~~~~~
------
::
\begin{equation*}
\frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} =
1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}}
{1+\frac{e^{-8\pi}} {1+\ldots} } } }
\end{equation*}
``\begin{equation*} \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\ldots} } } } \end{equation*}``
### Display
Display
-------
.. raw:: latex
@ -98,13 +134,21 @@ Source
\end{equation*}
A Rogers-Ramanujan Identity
---------------------------
===========================
Source
~~~~~~
------
::
``\begin{equation*} 1 + \frac{q^2}{(1-q)}+\frac{q^6}{(1-q)(1-q^2)}+\cdots = \prod_{j=0}^{\infty}\frac{1}{(1-q^{5j+2})(1-q^{5j+3})}, \quad\quad \text{for $|q|<1$}. \end{equation*}``
### Display
\begin{equation*}
1 + \frac{q^2}{(1-q)}+\frac{q^6}{(1-q)(1-q^2)}+\cdots =
\prod_{j=0}^{\infty}\frac{1}{(1-q^{5j+2})(1-q^{5j+3})},
\quad\quad \text{for $|q|<1$}.
\end{equation*}
Display
-------
.. raw:: latex
@ -115,13 +159,21 @@ Source
\end{equation*}
Maxwell's Equations
-------------------
===================
Source
~~~~~~
------
::
``\begin{align} \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ \nabla \cdot \vec{\mathbf{B}} & = 0 \end{align}``
### Display
\begin{align}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = 0
\end{align}
Display
-------
.. raw:: latex
@ -134,40 +186,40 @@ Source
Equation Numbering and References
=================================
--------------
Equation numbering and referencing will be available in a future version
of the Jupyter notebook.
Inline Typesetting (Mixing Markdown and TeX)
============================================
--------------
While display equations look good for a page of samples, the ability to
mix math and *formatted* **text** in a paragraph is also important.
Source
------
``This expression $\sqrt{3x-1}+(1+x)^2$ is an example of a TeX inline equation in a **[Markdown-formatted](http://daringfireball.net/projects/markdown/)** sentence.``
## Display This expression :math:`\sqrt{3x-1}+(1+x)^2` is an example of
a TeX inline equation in a
**`Markdown-formatted <http://daringfireball.net/projects/markdown/>`__**
::
This expression $\sqrt{3x-1}+(1+x)^2$ is an example of a TeX inline equation in a [Markdown-formatted](http://daringfireball.net/projects/markdown/) sentence.
Display
-------
This expression :math:`\sqrt{3x-1}+(1+x)^2` is an example of a TeX
inline equation in a
`Markdown-formatted <http://daringfireball.net/projects/markdown/>`__
sentence.
Other Syntax
============
--------------
You will notice in other places on the web that ``$$`` are needed
explicitly to begin and end MathJax typesetting. This is **not**
required if you will be using TeX environments, but the Jupyter notebook
will accept this syntax on legacy notebooks.
Source
~~~~~~
------
::
@ -203,7 +255,7 @@ Source
$$
Display
~~~~~~~
-------
.. math::

@ -0,0 +1,218 @@
.. _contents_api:
Contents API
============
.. currentmodule:: notebook.services.contents
The Jupyter Notebook web application provides a graphical interface for
creating, opening, renaming, and deleting files in a virtual filesystem.
The :class:`~manager.ContentsManager` class defines an abstract
API for translating these interactions into operations on a particular storage
medium. The default implementation,
:class:`~filemanager.FileContentsManager`, uses the local
filesystem of the server for storage and straightforwardly serializes notebooks
into JSON. Users can override these behaviors by supplying custom subclasses
of ContentsManager.
This section describes the interface implemented by ContentsManager subclasses.
We refer to this interface as the **Contents API**.
Data Model
----------
.. currentmodule:: notebook.services.contents.manager
Filesystem Entities
~~~~~~~~~~~~~~~~~~~
.. _notebook models:
ContentsManager methods represent virtual filesystem entities as dictionaries,
which we refer to as **models**.
Models may contain the following entries:
+--------------------+-----------+------------------------------+
| Key | Type |Info |
+====================+===========+==============================+
|**name** |unicode |Basename of the entity. |
+--------------------+-----------+------------------------------+
|**path** |unicode |Full |
| | |(:ref:`API-style<apipaths>`) |
| | |path to the entity. |
+--------------------+-----------+------------------------------+
|**type** |unicode |The entity type. One of |
| | |``"notebook"``, ``"file"`` or |
| | |``"directory"``. |
+--------------------+-----------+------------------------------+
|**created** |datetime |Creation date of the entity. |
+--------------------+-----------+------------------------------+
|**last_modified** |datetime |Last modified date of the |
| | |entity. |
+--------------------+-----------+------------------------------+
|**content** |variable |The "content" of the entity. |
| | |(:ref:`See |
| | |Below<modelcontent>`) |
+--------------------+-----------+------------------------------+
|**mimetype** |unicode or |The mimetype of ``content``, |
| |``None`` |if any. (:ref:`See |
| | |Below<modelcontent>`) |
+--------------------+-----------+------------------------------+
|**format** |unicode or |The format of ``content``, |
| |``None`` |if any. (:ref:`See |
| | |Below<modelcontent>`) |
+--------------------+-----------+------------------------------+
.. _modelcontent:
Certain model fields vary in structure depending on the ``type`` field of the
model. There are three model types: **notebook**, **file**, and **directory** .
- ``notebook`` models
- The ``format`` field is always ``"json"``.
- The ``mimetype`` field is always ``None``.
- The ``content`` field contains a
:class:`nbformat.notebooknode.NotebookNode` representing the .ipynb file
represented by the model. See the `NBFormat`_ documentation for a full
description.
- ``file`` models
- The ``format`` field is either ``"text"`` or ``"base64"``.
- The ``mimetype`` field is ``text/plain`` for text-format models and
``application/octet-stream`` for base64-format models.
- The ``content`` field is always of type ``unicode``. For text-format
file models, ``content`` simply contains the file's bytes after decoding
as UTF-8. Non-text (``base64``) files are read as bytes, base64 encoded,
and then decoded as UTF-8.
- ``directory`` models
- The ``format`` field is always ``"json"``.
- The ``mimetype`` field is always ``None``.
- The ``content`` field contains a list of :ref:`content-free<contentfree>`
models representing the entities in the directory.
.. note::
.. _contentfree:
In certain circumstances, we don't need the full content of an entity to
complete a Contents API request. In such cases, we omit the ``mimetype``,
``content``, and ``format`` keys from the model. This most commonly occurs
when listing a directory, in which circumstance we represent files within
the directory as content-less models to avoid having to recursively traverse
and serialize the entire filesystem.
**Sample Models**
.. sourcecode:: python
# Notebook Model with Content
{
'content': {
'metadata': {},
'nbformat': 4,
'nbformat_minor': 0,
'cells': [
{
'cell_type': 'markdown',
'metadata': {},
'source': 'Some **Markdown**',
},
],
},
'created': datetime(2015, 7, 25, 19, 50, 19, 19865),
'format': 'json',
'last_modified': datetime(2015, 7, 25, 19, 50, 19, 19865),
'mimetype': None,
'name': 'a.ipynb',
'path': 'foo/a.ipynb',
'type': 'notebook',
'writable': True,
}
# Notebook Model without Content
{
'content': None,
'created': datetime.datetime(2015, 7, 25, 20, 17, 33, 271931),
'format': None,
'last_modified': datetime.datetime(2015, 7, 25, 20, 17, 33, 271931),
'mimetype': None,
'name': 'a.ipynb',
'path': 'foo/a.ipynb',
'type': 'notebook',
'writable': True
}
API Paths
~~~~~~~~~
.. _apipaths:
ContentsManager methods represent the locations of filesystem resources as
**API-style paths**. Such paths are interpreted as relative to the root
directory of the notebook server. For compatibility across systems, the
following guarantees are made:
* Paths are always ``unicode``, not ``bytes``.
* Paths are not URL-escaped.
* Paths are always forward-slash (/) delimited, even on Windows.
* Leading and trailing slashes are stripped. For example, ``/foo/bar/buzz/``
becomes ``foo/bar/buzz``.
* The empty string (``""``) represents the root directory.
Writing a Custom ContentsManager
--------------------------------
The default ContentsManager is designed for users running the notebook as an
application on a personal computer. It stores notebooks as .ipynb files on the
local filesystem, and it maps files and directories in the Notebook UI to files
and directories on disk. It is possible to override how notebooks are stored
by implementing your own custom subclass of ``ContentsManager``. For example,
if you deploy the notebook in a context where you don't trust or don't have
access to the filesystem of the notebook server, it's possible to write your
own ContentsManager that stores notebooks and files in a database.
Required Methods
~~~~~~~~~~~~~~~~
A minimal complete implementation of a custom
:class:`~manager.ContentsManager` must implement the following
methods:
.. autosummary::
ContentsManager.get
ContentsManager.save
ContentsManager.delete_file
ContentsManager.rename_file
ContentsManager.file_exists
ContentsManager.dir_exists
ContentsManager.is_hidden
Customizing Checkpoints
-----------------------
TODO:
Testing
-------
.. currentmodule:: notebook.services.contents.tests
:mod:`notebook.services.contents.tests` includes several test suites written
against the abstract Contents API. This means that an excellent way to test a
new ContentsManager subclass is to subclass our tests to make them use your
ContentsManager.
.. note::
PGContents_ is an example of a complete implementation of a custom
``ContentsManager``. It stores notebooks and files in PostgreSQL_ and encodes
directories as SQL relations. PGContents also provides an example of how to
re-use the notebook's tests.
.. _NBFormat: http://nbformat.readthedocs.org/en/latest/index.html
.. _PGContents: https://github.com/quantopian/pgcontents
.. _PostgreSQL: http://www.postgresql.org/

@ -0,0 +1,12 @@
======================
Extending the Notebook
======================
Certain subsystems of the notebook server are designed to be extended or
overridden by users. These documents explain these systems, and show how to
override the notebook's defaults with your own custom behavior.
.. toctree::
:maxdepth: 2
contents

@ -9,5 +9,7 @@ The Jupyter notebook
config
public_server
security
extending/index
development
examples/Notebook/Examples and Tutorials Index
changelog

@ -27,6 +27,7 @@
.. Other python projects
.. _matplotlib: http://matplotlib.org
.. _nbviewer: http://nbviewer.jupyter.org
.. _nbconvert: http://nbconvert.readthedocs.org/en/latest/
.. Other tools and projects
.. _Markdown: http://daringfireball.net/projects/markdown/syntax

@ -65,14 +65,14 @@ colleagues.
Notebooks may be exported to a range of static formats, including HTML (for
example, for blog posts), reStructuredText, LaTeX, PDF, and slide shows, via
the new :ref:`nbconvert <nbconvert:index>` command.
the nbconvert_ command.
Furthermore, any ``.ipynb`` notebook document available from a public
URL can be shared via the `Jupyter Notebook Viewer <nbviewer>`_ (nbviewer_).
This service loads the notebook document from the URL and renders it as a
static web page. The results may thus be shared with a colleague, or as a
public blog post, without other users needing to install the Jupyter notebook
themselves. In effect, nbviewer_ is simply :ref:`nbconvert <nbconvert:index>` as
themselves. In effect, nbviewer_ is simply nbconvert_ as
a web service, so you can do your own static conversions with nbconvert,
without relying on nbviewer.
@ -80,7 +80,7 @@ without relying on nbviewer.
.. seealso::
:ref:`Details on the notebook JSON file format <nbformat:format_description>`
:ref:`Details on the notebook JSON file format <nbformat:notebook_file_format>`
Starting the notebook server
@ -267,7 +267,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 :ref:`nbconvert <nbconvert:index>`, raw cells arrive in the
When passed through nbconvert_, raw cells arrive in the
destination format unmodified. For example, this allows you to type full LaTeX
into a raw cell, which will only be rendered by LaTeX after conversion by
nbconvert.
@ -361,15 +361,13 @@ Plotting
One major feature of the Jupyter notebook is the ability to display plots that
are the output of running code cells. The IPython kernel is designed to work
seamlessly with the matplotlib_ plotting library to provide this functionality.
Specific plotting library integration is a feature of the kernel. See the
:ref:`plotting document <ipykernel:plotting>` of the IPython kernel for more
information.
Specific plotting library integration is a feature of the kernel.
Installing kernels
------------------
For information on how to install a Python kernel, refer to :ref:`IPython kernel's
installation document <ipykernel:kernel_install>`
For information on how to install a Python kernel, refer to the `IPython install
page <http://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>`_.
@ -405,3 +403,26 @@ You can generate a new notebook signing key with::
$ jupyter trust --reset
.. include:: links.txt
Browser Compatibility
---------------------
The Jupyter Notebook is officially supported on the following browsers:
* Chrome ≥ 13
* Safari ≥ 5
* Firefox ≥ 6
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)
Using Safari with HTTPS and an untrusted certificate is known to not work
(websockets will fail).

@ -4,7 +4,7 @@ Running a notebook server
=========================
The :ref:`Jupyter notebook <notebook>` web-application is based on a
The :doc:`Jupyter notebook <notebook>` web-application is based on a
server-client structure. This server uses a :ref:`two-process kernel
architecture <ipython:ipythonzmq>` based on ZeroMQ_, as well as Tornado_ for serving
HTTP requests. By default, a notebook server runs on http://127.0.0.1:8888/
@ -24,11 +24,11 @@ Securing a notebook server
You can protect your notebook server with a simple single password by
setting the :attr:`NotebookApp.password` configurable. You can prepare a
hashed password using the function :func:`IPython.lib.security.passwd`:
hashed password using the function :func:`notebook.auth.security.passwd`:
.. sourcecode:: ipython
In [1]: from IPython.lib import passwd
In [1]: from notebook.auth import passwd
In [2]: passwd()
Enter password:
Verify password:
@ -36,7 +36,7 @@ hashed password using the function :func:`IPython.lib.security.passwd`:
.. note::
:func:`~IPython.lib.security.passwd` can also take the password as a string
:func:`~notebook.auth.security.passwd` can also take the password as a string
argument. **Do not** pass it as an argument inside an IPython session, as it
will be saved in your input history.
@ -132,28 +132,6 @@ modifying ``jupyter_notebook_config.py``)::
c.NotebookApp.base_url = '/ipython/'
c.NotebookApp.webapp_settings = {'static_url_prefix':'/ipython/static/'}
Using a different notebook store
--------------------------------
By default, the notebook server stores the notebook documents that it saves as
files in the working directory of the notebook server, also known as the
``notebook_dir``. This logic is implemented in the
:class:`FileNotebookManager` class. However, the server can be configured to
use a different notebook manager class, which can
store the notebooks in a different format.
The bookstore_ package currently allows users to store notebooks on Rackspace
CloudFiles or OpenStack Swift based object stores.
Writing a notebook manager is as simple as extending the base class
:class:`NotebookManager`. The simple_notebook_manager_ provides a great example
of an in memory notebook manager, created solely for the purpose of
illustrating the notebook manager API.
.. _bookstore: https://github.com/rgbkrk/bookstore
.. _simple_notebook_manager: https://github.com/khinsen/simple_notebook_manager
Known issues
------------

@ -1,114 +0,0 @@
var fork = require('child_process').fork;
var fs = require('fs');
var path = require('path');
var through = require('through');
var gulp = require('gulp');
var less = require('gulp-less');
var newer = require('gulp-newer');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');
// now some dev nice utilities.
var livereload = require('gulp-livereload');
gulp.task('css', function () {
return gulp.src('./notebook/static/style/*.less')
.pipe(sourcemaps.init())
.pipe(less({
paths: [ path.join(__dirname, 'less', 'includes') ]
}))
// we don't minify on purpose as it removes rules
.pipe(rename({
suffix: '.min'
}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./notebook/static/style'))
.pipe(livereload());
});
function build_main(name, callback) {
// build main.min.js for a given application name
// run in a subprocess to allow parallel builds
// clone requirejs config
var p = fork('./build-main.js', [name]);
p.on('exit', function (code, status) {
if (code) {
callback(new Error("Build failed"));
} else {
callback();
}
});
return;
}
// build notebook-js, edit-js, etc. tasks
// which enables parallelism
var apps = ['notebook', 'tree', 'edit', 'terminal', 'auth'];
apps.map(function (name) {
gulp.task(name + '-js', function (finish) {
var s = path.join('notebook', 'static');
var src = path.join(s, name, 'js', 'main.js');
var rel_dest = path.join(name, 'js', 'main.min.js');
var dest = path.join(s, rel_dest);
var sources = [
path.join(s, name, 'js', '*.js'),
path.join(s, "base", 'js', '*.js'),
path.join(s, "auth", 'js', '*.js'),
path.join(s, "services", 'config.js'),
];
// for required_components
if (name === 'notebook') {
sources.push(path.join(s, "services", '**', '*.js'));
}
fs.readdirSync(path.join(s, 'components')).map(function (c) {
if (c !== 'MathJax') {
// skip MathJax because it has tons of files and makes everything super slow
sources.push(path.join(s, 'components', c, '**', '*.js'));
}
});
// sources is a greedy list, containing all dependencies plus some for simplicity.
gulp.src(sources, {base: s})
.pipe(newer(dest))
.pipe(through(function(file) {
// if any dependency changed, update main.min.js
console.log("A dependency has changed, updating " + rel_dest);
// pause halts the pipeline
this.pause();
build_main(name, finish);
return;
}))
.on('end', function () {
// if we get here, no dependency is newer than the target
console.log(rel_dest + " up to date");
finish();
});
});
});
gulp.task('js', apps.map(function (name) { return name + '-js'; }));
gulp.task('watch', function() {
livereload.listen();
gulp.watch('notebook/static/**/*.less', ['css']);
var s = path.join('notebook', 'static');
function alljs(name) {
return path.join(s, name, '**', '*.js');
}
var common_js = ['components', 'base', 'auth', 'services'].map(alljs);
gulp.watch(common_js, ['js']);
apps.map(function (name) {
gulp.watch([
alljs(name),
'!' + path.join(s, name, 'js', 'main.min.js'),
], [name + '-js']);
});
});

@ -46,7 +46,7 @@ def pkg_commit_hash(pkg_path):
repo_commit, _ = proc.communicate()
if repo_commit:
return 'repository', repo_commit.strip().decode('ascii')
return '(none found)', u'<not found>'
return u'', u''
def pkg_info(pkg_path):

@ -1,2 +1,2 @@
version_info = (4, 0, 0, 'dev')
version_info = (4, 0, 7, 'dev')
__version__ = '.'.join(map(str, version_info))

@ -85,7 +85,8 @@ class NbconvertFileHandler(IPythonHandler):
model = self.contents_manager.get(path=path)
name = model['name']
if model['type'] != 'notebook':
raise web.HTTPError(400, "Not a notebook: %s" % path)
# not a notebook, redirect to files
return FilesRedirectHandler.redirect_to_files(self, path)
self.set_header('Last-Modified', model['last_modified'])
@ -97,7 +98,8 @@ class NbconvertFileHandler(IPythonHandler):
"name": name[:name.rfind('.')],
"modified_date": (model['last_modified']
.strftime(text.date_format))
}
},
"config_dir": self.application.settings['config_dir'],
}
)
except Exception as e:
@ -131,7 +133,10 @@ class NbconvertPostHandler(IPythonHandler):
nbnode = from_dict(model['content'])
try:
output, resources = exporter.from_notebook_node(nbnode)
output, resources = exporter.from_notebook_node(nbnode, resources={
"metadata": {"name": name[:name.rfind('.')],},
"config_dir": self.application.settings['config_dir'],
})
except Exception as e:
raise web.HTTPError(500, "nbconvert failed: %s" % e)
@ -157,5 +162,4 @@ default_handlers = [
(r"/nbconvert/%s" % _format_regex, NbconvertPostHandler),
(r"/nbconvert/%s%s" % (_format_regex, path_regex),
NbconvertFileHandler),
(r"/nbconvert/html%s" % path_regex, FilesRedirectHandler),
]

@ -288,6 +288,9 @@ class InstallNBExtensionApp(JupyterApp):
verbose = Enum((0,1,2), default_value=1, config=True,
help="Verbosity level"
)
def _config_file_name_default(self):
return 'jupyter_notebook_config'
def install_extensions(self):
if len(self.extra_args)>1:
@ -316,6 +319,71 @@ class InstallNBExtensionApp(JupyterApp):
print(str(e), file=sys.stderr)
self.exit(1)
class EnableNBExtensionApp(JupyterApp):
name = "jupyter nbextension enable"
version = __version__
description = "Configure an nbextension to be automatically loaded"
section = Unicode('notebook', config=True,
help=("Which config section to add the extension to. "
"'common' will affect all pages.")
)
aliases = {'section': 'EnableNBExtensionApp.section',
}
def _config_file_name_default(self):
return 'jupyter_notebook_config'
def enable_nbextension(self, name):
# Local import to avoid circular import issue on Py 2
from .services.config import ConfigManager
cm = ConfigManager(parent=self, config=self.config)
cm.update(self.section, {"load_extensions": {name: True}})
def start(self):
if not self.extra_args:
sys.exit('No extensions specified')
elif len(self.extra_args) > 1:
sys.exit('Please specify one extension at a time')
self.enable_nbextension(self.extra_args[0])
class DisableNBExtensionApp(JupyterApp):
name = "jupyter nbextension disable"
version = __version__
description = "Remove the configuration to automatically load an extension"
section = Unicode('notebook', config=True,
help=("Which config section to remove the extension from. "
"This should match the one it was previously added to.")
)
aliases = {'section': 'DisableNBExtensionApp.section',
}
def _config_file_name_default(self):
return 'jupyter_notebook_config'
def disable_nbextension(self, name):
# Local import to avoid circular import issue on Py 2
from .services.config import ConfigManager
cm = ConfigManager(parent=self, config=self.config)
if name not in cm.get(self.section).get('load_extensions', {}):
sys.exit('{} is not enabled in section {}'.format(name, self.section))
# We're using a dict as a set - updating with None removes the key
cm.update(self.section, {"load_extensions": {name: None}})
def start(self):
if not self.extra_args:
sys.exit('No extensions specified')
elif len(self.extra_args) > 1:
sys.exit('Please specify one extension at a time')
self.disable_nbextension(self.extra_args[0])
class NBExtensionApp(JupyterApp):
name = "jupyter nbextension"
version = __version__
@ -325,6 +393,8 @@ class NBExtensionApp(JupyterApp):
install=(InstallNBExtensionApp,
"""Install notebook extensions"""
),
enable=(EnableNBExtensionApp, "Enable a notebook extension"),
disable=(DisableNBExtensionApp, "Disable a notebook extension"),
)
def start(self):

@ -160,7 +160,9 @@ class NotebookWebApplication(web.Application):
_template_path = (_template_path,)
template_path = [os.path.expanduser(path) for path in _template_path]
jenv_opt = jinja_env_options if jinja_env_options else {}
jenv_opt = {"autoescape": True}
jenv_opt.update(jinja_env_options if jinja_env_options else {})
env = Environment(loader=FileSystemLoader(template_path), **jenv_opt)
sys_info = get_sys_info()
@ -207,6 +209,7 @@ class NotebookWebApplication(web.Application):
websocket_url=ipython_app.websocket_url,
mathjax_url=ipython_app.mathjax_url,
config=ipython_app.config,
config_dir=ipython_app.config_dir,
jinja2_env=env,
terminals_available=False, # Set later if terminals are available
)
@ -237,6 +240,20 @@ class NotebookWebApplication(web.Application):
handlers.extend(load_handlers('services.nbconvert.handlers'))
handlers.extend(load_handlers('services.kernelspecs.handlers'))
handlers.extend(load_handlers('services.security.handlers'))
# BEGIN HARDCODED WIDGETS HACK
try:
import ipywidgets
handlers.append(
(r"/nbextensions/widgets/(.*)", FileFindHandler, {
'path': ipywidgets.find_static_assets(),
'no_cache_paths': ['/'], # don't cache anything in nbextensions
}),
)
except:
app_log.warn('ipywidgets package not installed. Widgets are unavailable.')
# END HARDCODED WIDGETS HACK
handlers.append(
(r"/nbextensions/(.*)", FileFindHandler, {
'path': settings['nbextensions_path'],
@ -572,7 +589,7 @@ class NotebookApp(JupyterApp):
self.log.warn("base_project_url is deprecated, use base_url")
self.base_url = new
extra_static_paths = List(Unicode, config=True,
extra_static_paths = List(Unicode(), config=True,
help="""Extra paths to search for serving static files.
This allows adding javascript/css to be available from the notebook server machine,
@ -584,7 +601,7 @@ class NotebookApp(JupyterApp):
"""return extra paths + the default location"""
return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
static_custom_path = List(Unicode,
static_custom_path = List(Unicode(),
help="""Path to search for custom.js, css"""
)
def _static_custom_path_default(self):
@ -596,7 +613,7 @@ class NotebookApp(JupyterApp):
DEFAULT_STATIC_FILES_PATH)
]
extra_template_paths = List(Unicode, config=True,
extra_template_paths = List(Unicode(), config=True,
help="""Extra paths to search for serving jinja templates.
Can be used to override templates from notebook.templates."""
@ -607,7 +624,7 @@ class NotebookApp(JupyterApp):
"""return extra paths + the default locations"""
return self.extra_template_paths + DEFAULT_TEMPLATE_PATH_LIST
extra_nbextensions_path = List(Unicode, config=True,
extra_nbextensions_path = List(Unicode(), config=True,
help="""extra paths to look for Javascript notebook extensions"""
)
@ -800,7 +817,7 @@ class NotebookApp(JupyterApp):
self.config_manager = self.config_manager_class(
parent=self,
log=self.log,
config_dir=self.config_dir,
config_dir=os.path.join(self.config_dir, 'nbconfig'),
)
def init_logging(self):
@ -889,7 +906,7 @@ class NotebookApp(JupyterApp):
def init_terminals(self):
try:
from .terminal import initialize
initialize(self.web_app)
initialize(self.web_app, self.notebook_dir, self.connection_url)
self.web_app.settings['terminals_available'] = True
except ImportError as e:
log = self.log.debug if sys.platform == 'win32' else self.log.warn
@ -960,20 +977,6 @@ class NotebookApp(JupyterApp):
"""Check the components submodule, and warn if it's unclean"""
# TODO: this should still check, but now we use bower, not git submodule
pass
def init_kernel_specs(self):
"""Check that the IPython kernel is present, if available"""
try:
self.kernel_spec_manager.get_kernel_spec(NATIVE_KERNEL_NAME)
except NoSuchKernel:
try:
from ipykernel.kernelspec import install
except ImportError:
self.log.warn("IPython kernel not available")
else:
self.log.warn("Installing IPython kernel spec")
install(kernel_spec_manager=self.kernel_spec_manager, user=True)
def init_server_extensions(self):
"""Load any extensions specified by config.
@ -1002,7 +1005,6 @@ class NotebookApp(JupyterApp):
self.init_configurables()
self.init_components()
self.init_webapp()
self.init_kernel_specs()
self.init_terminals()
self.init_signal()
self.init_server_extensions()

@ -67,7 +67,7 @@ class GenericCheckpointsMixin(object):
- get_notebook_checkpoint(self, checkpoint_id, path)
To create a generic CheckpointManager, add this mixin to a class that
implement the above three methods plus the remaining Checkpoints API
implement the above four methods plus the remaining Checkpoints API
methods:
- delete_checkpoint(self, checkpoint_id, path)
@ -118,10 +118,25 @@ class GenericCheckpointsMixin(object):
"""
raise NotImplementedError("must be implemented in a subclass")
def get_checkpoint(self, checkpoint_id, path, type):
"""Get the content of a checkpoint.
def get_file_checkpoint(self, checkpoint_id, path):
"""Get the content of a checkpoint for a non-notebook file.
Returns an unvalidated model with the same structure as
the return value of ContentsManager.get
Returns a dict of the form:
{
'type': 'file',
'content': <str>,
'format': {'text','base64'},
}
"""
raise NotImplementedError("must be implemented in a subclass")
def get_notebook_checkpoint(self, checkpoint_id, path):
"""Get the content of a checkpoint for a notebook.
Returns a dict of the form:
{
'type': 'notebook',
'content': <output of nbformat.read>,
}
"""
raise NotImplementedError("must be implemented in a subclass")

@ -142,7 +142,7 @@ class GenericFileCheckpoints(GenericCheckpointsMixin, FileCheckpoints):
ContentsManager.
"""
def create_file_checkpoint(self, content, format, path):
"""Create a checkpoint from the current content of a notebook."""
"""Create a checkpoint from the current content of a file."""
path = path.strip('/')
# only the one checkpoint ID:
checkpoint_id = u"checkpoint"
@ -168,7 +168,7 @@ class GenericFileCheckpoints(GenericCheckpointsMixin, FileCheckpoints):
return self.checkpoint_model(checkpoint_id, os_checkpoint_path)
def get_notebook_checkpoint(self, checkpoint_id, path):
"""Get a checkpoint for a notebook."""
path = path.strip('/')
self.log.info("restoring %s from checkpoint %s", path, checkpoint_id)
os_checkpoint_path = self.checkpoint_path(checkpoint_id, path)
@ -185,6 +185,7 @@ class GenericFileCheckpoints(GenericCheckpointsMixin, FileCheckpoints):
}
def get_file_checkpoint(self, checkpoint_id, path):
"""Get a checkpoint for a file."""
path = path.strip('/')
self.log.info("restoring %s from checkpoint %s", path, checkpoint_id)
os_checkpoint_path = self.checkpoint_path(checkpoint_id, path)

@ -53,7 +53,7 @@ class ContentsManager(LoggingConfigurable):
def _notary_default(self):
return sign.NotebookNotary(parent=self)
hide_globs = List(Unicode, [
hide_globs = List(Unicode(), [
u'__pycache__', '*.pyc', '*.pyo',
'.DS_Store', '*.so', '*.dylib', '*~',
], config=True, help="""
@ -124,7 +124,7 @@ class ContentsManager(LoggingConfigurable):
# implemented in subclasses.
def dir_exists(self, path):
"""Does the API-style path (directory) actually exist?
"""Does a directory exist at the given path?
Like os.path.isdir
@ -143,7 +143,7 @@ class ContentsManager(LoggingConfigurable):
raise NotImplementedError
def is_hidden(self, path):
"""Does the API style path correspond to a hidden directory or file?
"""Is path a hidden directory or file?
Parameters
----------
@ -168,10 +168,8 @@ class ContentsManager(LoggingConfigurable):
Parameters
----------
name : string
The name of the file you are checking.
path : string
The relative path to the file's directory (with '/' as separator)
The API path of a file to check for.
Returns
-------
@ -188,7 +186,7 @@ class ContentsManager(LoggingConfigurable):
Parameters
----------
path : string
The relative path to the file's directory (with '/' as separator)
The API path of a file or directory to check for.
Returns
-------
@ -198,23 +196,25 @@ class ContentsManager(LoggingConfigurable):
return self.file_exists(path) or self.dir_exists(path)
def get(self, path, content=True, type=None, format=None):
"""Get the model of a file or directory with or without content."""
"""Get a file or directory model."""
raise NotImplementedError('must be implemented in a subclass')
def save(self, model, path):
"""Save the file or directory and return the model with no content.
"""
Save a file or directory model to path.
Save implementations should call self.run_pre_save_hook(model=model, path=path)
prior to writing any data.
Should return the saved model with no content. Save implementations
should call self.run_pre_save_hook(model=model, path=path) prior to
writing any data.
"""
raise NotImplementedError('must be implemented in a subclass')
def delete_file(self, path):
"""Delete file or directory by path."""
"""Delete the file or directory at path."""
raise NotImplementedError('must be implemented in a subclass')
def rename_file(self, old_path, new_path):
"""Rename a file."""
"""Rename a file or directory."""
raise NotImplementedError('must be implemented in a subclass')
# ContentsManager API part 2: methods that have useable default

@ -24,7 +24,7 @@ class MappingKernelManager(MultiKernelManager):
def _kernel_manager_class_default(self):
return "jupyter_client.ioloop.IOLoopKernelManager"
kernel_argv = List(Unicode)
kernel_argv = List(Unicode())
root_dir = Unicode(config=True)

@ -75,7 +75,7 @@ define(function(){
jglobal('ClusterList','tree/js/clusterlist');
jglobal('ClusterItem','tree/js/clusterlist');
Jupyter.version = "4.0.0.dev";
Jupyter.version = "4.0.7.dev";
Jupyter._target = '_blank';
return Jupyter;
});

@ -842,6 +842,7 @@ define([
};
var utils = {
load_extension: load_extension,
load_extensions: load_extensions,
load_extensions_from_config: load_extensions_from_config,
regex_split : regex_split,

@ -40,7 +40,7 @@
* IPython.toolbar.add_buttons_group([
* {
* 'label' : 'run qtconsole',
* 'icon' : 'icon-terminal', // select your icon from http://fortawesome.github.io/Font-Awesome/icons
* 'icon' : 'fa-terminal', // select your icon from http://fortawesome.github.io/Font-Awesome/icons
* 'callback': function () {
* IPython.notebook.kernel.execute('%qtconsole')
* }

@ -100,6 +100,35 @@ define(function(require){
}
}
},
'extend-selection-previous' : {
help: 'extend selection above',
help_index : 'dc',
handler : function (env) {
var index = env.notebook.get_selected_index();
if (index !== 0 && index !== null) {
env.notebook.extend_selection('up');
env.notebook.focus_cell();
}
}
},
'extend-selection-next' : {
help: 'extend selection below',
help_index : 'dd',
handler : function (env) {
var index = env.notebook.get_selected_index();
if (index !== (env.notebook.ncells()-1) && index !== null) {
env.notebook.extend_selection('down');
env.notebook.focus_cell();
}
}
},
'reset-selection': {
help: 'clear selected cells',
help_index: 'de',
handler: function(env) {
env.notebook.reset_selection();
}
},
'cut-selected-cell' : {
icon: 'fa-cut',
help_index : 'ee',
@ -288,6 +317,13 @@ define(function(require){
env.notebook.merge_cell_below();
}
},
'merge-selected-cells' : {
help : 'merge selected cells',
help_index: 'el',
handler: function(env) {
env.notebook.merge_selected_cells();
}
},
'close-pager' : {
help_index : 'gd',
handler : function (env) {

@ -55,6 +55,8 @@ define([
this.placeholder = config.placeholder || '';
this.selected = false;
this.in_selection = false;
this.selection_anchor = false;
this.rendered = false;
this.mode = 'command';
@ -142,7 +144,7 @@ define([
* Call after this.element exists to initialize the css classes
* related to selected, rendered and mode.
*/
if (this.selected) {
if (this.in_selection) {
this.element.addClass('selected');
} else {
this.element.addClass('unselected');
@ -254,6 +256,7 @@ define([
this.element.addClass('selected');
this.element.removeClass('unselected');
this.selected = true;
this.in_selection = true;
return true;
} else {
return false;
@ -261,19 +264,21 @@ define([
};
/**
* handle cell level logic when a cell is unselected
* handle cell level logic when the cursor moves away from a cell
* @method unselect
* @param {bool} leave_selected - true to move cursor away and extend selection
* @return is the action being taken
*/
Cell.prototype.unselect = function () {
if (this.selected) {
Cell.prototype.unselect = function (leave_selected) {
var was_selected_cell = this.selected;
this.selected = false;
if ((!leave_selected) && this.in_selection) {
this.in_selection = false;
this.selection_anchor = false;
this.element.addClass('unselected');
this.element.removeClass('selected');
this.selected = false;
return true;
} else {
return false;
}
return was_selected_cell;
};
/**

@ -535,14 +535,14 @@ define([
};
/**
* handle cell level logic when a cell is unselected
* handle cell level logic when the cursor moves away from a cell
* @method unselect
* @return is the action being taken
*/
CodeCell.prototype.unselect = function () {
var cont = Cell.prototype.unselect.apply(this);
CodeCell.prototype.unselect = function (leave_selected) {
var cont = Cell.prototype.unselect.apply(this, [leave_selected]);
if (cont) {
// When a code cell is usnelected, make sure that the corresponding
// When a code cell is unselected, make sure that the corresponding
// tooltip and completer to that cell is closed.
this.tooltip.remove_and_cancel_tooltip(true);
if (this.completer !== null) {

@ -86,7 +86,7 @@ define([
return {
'shift-space': 'ipython.scroll-up',
'shift-v' : 'ipython.paste-cell-before',
'shift-m' : 'ipython.merge-selected-cell-with-cell-after',
'shift-m' : 'ipython.merge-selected-cells',
'shift-o' : 'ipython.toggle-output-scrolling-selected-cell',
'enter' : 'ipython.enter-edit-mode',
'space' : 'ipython.scroll-down',
@ -98,6 +98,8 @@ define([
'up' : 'ipython.select-previous-cell',
'k' : 'ipython.select-previous-cell',
'j' : 'ipython.select-next-cell',
'shift-k': 'ipython.extend-selection-previous',
'shift-j': 'ipython.extend-selection-next',
'x' : 'ipython.cut-selected-cell',
'c' : 'ipython.copy-selected-cell',
'v' : 'ipython.paste-cell-after',

@ -50,6 +50,12 @@ require([
) {
"use strict";
// BEGIN HARDCODED WIDGETS HACK
utils.load_extension('widgets/notebook/js/extension').catch(function () {
console.warn('ipywidgets package not installed. Widgets are not available.');
});
// END HARDCODED WIDGETS HACK
// compat with old IPython, remove for IPython > 3.0
window.CodeMirror = CodeMirror;
@ -127,17 +133,14 @@ require([
page.show();
var first_load = function () {
events.one('notebook_loaded.Notebook', function () {
var hash = document.location.hash;
if (hash) {
document.location.hash = '';
document.location.hash = hash;
}
notebook.set_autosave_interval(notebook.minimum_autosave_interval);
// only do this once
events.off('notebook_loaded.Notebook', first_load);
};
events.on('notebook_loaded.Notebook', first_load);
});
IPython.page = page;
IPython.notebook = notebook;
@ -151,8 +154,11 @@ require([
IPython.keyboard_manager = keyboard_manager;
IPython.save_widget = save_widget;
IPython.tooltip = notebook.tooltip;
events.trigger('app_initialized.NotebookApp');
try {
events.trigger('app_initialized.NotebookApp');
} catch (e) {
console.error("Error in app_initialized callback", e);
}
utils.load_extensions_from_config(config_section);
utils.load_extensions_from_config(common_config);
notebook.load_notebook(common_options.notebook_path);

@ -113,12 +113,16 @@ define([
this.element.find('#download_ipynb').click(function () {
var base_url = that.notebook.base_url;
var notebook_path = that.notebook.notebook_path;
var w = window.open('');
var url = utils.url_join_encode(base_url, 'files', notebook_path)
+ '?download=1';
if (that.notebook.dirty) {
that.notebook.save_notebook({async : false});
that.notebook.save_notebook().then(function() {
w.location = url;
});
} else {
w.location = url;
}
var url = utils.url_join_encode(base_url, 'files', notebook_path);
window.open(url + '?download=1');
});
this.element.find('#print_preview').click(function () {

@ -114,6 +114,7 @@ define(function (require) {
this.next_prompt_number = 1;
this.session = null;
this.kernel = null;
this.kernel_busy = false;
this.clipboard = null;
this.undelete_backup = null;
this.undelete_index = null;
@ -249,6 +250,14 @@ define(function (require) {
var cm_mode = langinfo.codemirror_mode || langinfo.name || 'null';
that.set_codemirror_mode(cm_mode);
});
this.events.on('kernel_idle.Kernel', function () {
that.kernel_busy = false;
});
this.events.on('kernel_busy.Kernel', function () {
that.kernel_busy = true;
});
var collapse_time = function (time) {
var app_height = $('#ipython-main-app').height(); // content height
@ -274,7 +283,7 @@ define(function (require) {
var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
expand_time(time);
});
// Firefox 22 broke $(window).on("beforeunload")
// I'm not sure why or how.
window.onbeforeunload = function (e) {
@ -301,6 +310,10 @@ define(function (require) {
return "Unsaved changes will be lost.";
}
}
// if the kernel is busy, prompt the user if hes sure
if (that.kernel_busy) {
return "The Kernel is busy, outputs may be lost.";
}
// IE treats null as a string. Instead just return which will avoid the dialog.
return;
};
@ -587,6 +600,46 @@ define(function (require) {
return result;
};
/**
* Get the index of the anchor cell for range selection
*
* @return {integer} The anchor cell's numeric index
*/
Notebook.prototype.get_selection_anchor = function() {
var result = null;
this.get_cell_elements().filter(function (index) {
if ($(this).data("cell").selection_anchor === true) {
result = index;
}
});
return result;
};
/**
* Get an array of the cells in the currently selected range
*
* @return {Array} The selected cells
*/
Notebook.prototype.get_selected_cells = function () {
return this.get_cells().filter(function(cell) {
return cell.in_selection;
});
};
/**
* Get the indices of the currently selected range of cells.
*
* @return {Array} The selected cells' numeric indices
*/
Notebook.prototype.get_selected_indices = function () {
var result = [];
this.get_cell_elements().filter(function (index) {
if ($(this).data("cell").in_selection === true) {
result.push(index);
}
});
return result;
};
// Cell selection.
@ -605,23 +658,27 @@ define(function (require) {
if (this.mode !== 'command') {
this.command_mode();
}
this.get_cell(sindex).unselect();
}
var cell = this.get_cell(index);
cell.select();
if (cell.cell_type === 'heading') {
this.events.trigger('selected_cell_type_changed.Notebook',
{'cell_type':cell.cell_type,level:cell.level}
);
} else {
this.events.trigger('selected_cell_type_changed.Notebook',
{'cell_type':cell.cell_type}
);
var current_selection = this.get_selected_cells();
for (var i=0; i<current_selection.length; i++) {
current_selection[i].unselect()
}
var cell = this._select(index);
cell.selection_anchor = true
}
return this;
};
Notebook.prototype._select = function(index) {
var cell = this.get_cell(index);
cell.select();
this.events.trigger('selected_cell_type_changed.Notebook',
{'cell_type':cell.cell_type}
);
return cell;
};
/**
* Programmatically select the next cell.
*
@ -644,6 +701,42 @@ define(function (require) {
return this;
};
/**
* Extend the selected range
*
* @param {string} direction - 'up' or 'down
*/
Notebook.prototype.extend_selection = function(direction) {
var anchor_ix = this.get_selection_anchor();
var cursor_ix = this.get_selected_index();
var range_direction = (cursor_ix > anchor_ix) ? 'down' : 'up';
var contracting = (cursor_ix !== anchor_ix) &&
(direction !== range_direction);
var ix_delta = (direction === 'up') ? -1 : 1;
var new_ix = cursor_ix + ix_delta;
if (new_ix < 0 || new_ix >= this.ncells()) {
return false;
}
if (this.mode !== 'command') {
this.command_mode();
}
this.get_cell(cursor_ix).unselect(!contracting);
this._select(new_ix);
return true;
};
/**
* Clear selection of multiple cells (except the cell at the cursor)
*/
Notebook.prototype.reset_selection = function() {
var current_selection = this.get_selected_cells();
for (var i=0; i<current_selection.length; i++) {
if (!current_selection[i].selected) {
current_selection[i].unselect()
}
}
};
// Edit/Command mode
@ -697,6 +790,7 @@ define(function (require) {
if (cell && this.mode !== 'edit') {
cell.edit_mode();
this.mode = 'edit';
this.reset_selection();
this.events.trigger('edit_mode.Notebook');
this.keyboard_manager.edit_mode();
}
@ -1277,36 +1371,71 @@ define(function (require) {
};
/**
* Merge the selected cell into the cell above it.
* Merge a series of cells into one
*
* @param {Array} indices - the numeric indices of the cells to be merged
* @param {bool} into_last - merge into the last cell instead of the first
*/
Notebook.prototype.merge_cell_above = function () {
var index = this.get_selected_index();
var cell = this.get_cell(index);
var render = cell.rendered;
if (!cell.is_mergeable()) {
Notebook.prototype.merge_cells = function(indices, into_last) {
if (indices.length <= 1) {
return;
}
if (index > 0) {
var upper_cell = this.get_cell(index-1);
if (!upper_cell.is_mergeable()) {
for (var i=0; i < indices.length; i++) {
if (!this.get_cell(indices[i]).is_mergeable()) {
return;
}
var upper_text = upper_cell.get_text();
var text = cell.get_text();
if (cell instanceof codecell.CodeCell) {
cell.set_text(upper_text+'\n'+text);
} else {
cell.unrender(); // Must unrender before we set_text.
cell.set_text(upper_text+'\n\n'+text);
if (render) {
// The rendered state of the final cell should match
// that of the original selected cell;
cell.render();
}
}
var target = this.get_cell(into_last ? indices.pop() : indices.shift());
// Get all the cells' contents
var contents = [];
for (i=0; i < indices.length; i++) {
contents.push(this.get_cell(indices[i]).get_text());
}
if (into_last) {
contents.push(target.get_text())
} else {
contents.unshift(target.get_text())
}
// Update the contents of the target cell
if (target instanceof codecell.CodeCell) {
target.set_text(contents.join('\n\n'))
} else {
var was_rendered = target.rendered;
target.unrender(); // Must unrender before we set_text.
target.set_text(contents.join('\n\n'));
if (was_rendered) {
// The rendered state of the final cell should match
// that of the original selected cell;
target.render();
}
this.delete_cell(index-1);
this.select(this.find_cell_index(cell));
}
// Delete the other cells
// If we started deleting cells from the top, the later indices would
// get offset. We sort them into descending order to avoid that.
indices.sort(function(a, b) {return b-a;});
for (i=0; i < indices.length; i++) {
this.delete_cell(indices[i]);
}
this.select(this.find_cell_index(target));
};
/**
* Merge the selected range of cells
*/
Notebook.prototype.merge_selected_cells = function() {
this.merge_cells(this.get_selected_indices());
};
/**
* Merge the selected cell into the cell above it.
*/
Notebook.prototype.merge_cell_above = function () {
var index = this.get_selected_index();
this.merge_cells([index-1, index], true)
};
/**
@ -1314,32 +1443,7 @@ define(function (require) {
*/
Notebook.prototype.merge_cell_below = function () {
var index = this.get_selected_index();
var cell = this.get_cell(index);
var render = cell.rendered;
if (!cell.is_mergeable()) {
return;
}
if (index < this.ncells()-1) {
var lower_cell = this.get_cell(index+1);
if (!lower_cell.is_mergeable()) {
return;
}
var lower_text = lower_cell.get_text();
var text = cell.get_text();
if (cell instanceof codecell.CodeCell) {
cell.set_text(text+'\n'+lower_text);
} else {
cell.unrender(); // Must unrender before we set_text.
cell.set_text(text+'\n\n'+lower_text);
if (render) {
// The rendered state of the final cell should match
// that of the original selected cell;
cell.render();
}
}
this.delete_cell(index+1);
this.select(this.find_cell_index(cell));
}
this.merge_cells([index, index+1], false)
};
@ -1637,13 +1741,13 @@ define(function (require) {
that.clear_all_output();
that.kernel.restart();
},
},
"Restart" : {
"class" : "btn-warning",
"click" : function() {
that.kernel.restart();
}
},
}
}
});
};

@ -595,7 +595,7 @@ define([
var append_markdown = function(markdown, md, element) {
var type = 'text/markdown';
var toinsert = this.create_output_subarea(md, "output_markdown", type);
var toinsert = this.create_output_subarea(md, "output_markdown rendered_html", type);
var text_and_math = mathjaxutils.remove_math(markdown);
var text = text_and_math[0];
var math = text_and_math[1];
@ -614,7 +614,7 @@ define([
* We just eval the JS code, element appears in the local scope.
*/
var type = 'application/javascript';
var toinsert = this.create_output_subarea(md, "output_javascript", type);
var toinsert = this.create_output_subarea(md, "output_javascript rendered_html", type);
this.keyboard_manager.register_events(toinsert);
element.append(toinsert);

@ -1,6 +1,6 @@
.completions {
position: absolute;
z-index: 10;
z-index: 110;
overflow: hidden;
border: 1px solid @border_color;
.corner-all;

@ -862,7 +862,7 @@ define([
this._msg_queue = this._msg_queue.then(function() {
return serialize.deserialize(e.data);
}).then(function(msg) {return that._finish_ws_message(msg);})
.catch(utils.reject("Couldn't process kernel message", true));
.catch(function(error) {console.error("Couldn't process kernel message", error) });
};
Kernel.prototype._finish_ws_message = function (msg) {

@ -295,7 +295,11 @@ define([
for (var i=0; i<len; i++) {
model = list.content[i];
item = this.new_item(i+offset, true);
this.add_link(model, item);
try {
this.add_link(model, item);
} catch(err) {
console.log('Error adding link: ' + err)
}
}
// Trigger an event when we've finished drawing the notebook list.
events.trigger('draw_notebook_list.NotebookList');

@ -3,7 +3,7 @@
{% block stylesheet %}
{% if mathjax_url %}
<script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
<script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full,Safe&delayStartupUntil=configured" charset="utf-8"></script>
{% endif %}
<script type="text/javascript">
// MathJax disabled, set as null to distingish from *missing* MathJax,
@ -265,7 +265,10 @@ data-notebook-path="{{notebook_path}}"
{% for helplinks in sections %}
{% for link in helplinks %}
<li><a href="{{link[0]}}" {{'target="_blank" title="Opens in a new window"' if link[2]}}>
{{'<i class="fa fa-external-link menu-icon pull-right"></i>' if link[2]}}
{% if link[2] %}
<i class="fa fa-external-link menu-icon pull-right"></i>
{% endif %}
{{link[1]}}
</a></li>
{% endfor %}
@ -319,7 +322,7 @@ data-notebook-path="{{notebook_path}}"
{% block script %}
{{super()}}
<script type="text/javascript">
sys_info = {{sys_info}};
sys_info = {{sys_info|safe}};
</script>
<script src="{{ static_url("components/text-encoding/lib/encoding.js") }}" charset="utf-8"></script>

@ -12,9 +12,14 @@ from notebook.utils import url_path_join as ujoin
from .handlers import TerminalHandler, TermSocket
from . import api_handlers
def initialize(webapp):
def initialize(webapp, notebook_dir, connection_url):
shell = os.environ.get('SHELL') or 'sh'
terminal_manager = webapp.settings['terminal_manager'] = NamedTermManager(shell_command=[shell])
terminal_manager = webapp.settings['terminal_manager'] = NamedTermManager(
shell_command=[shell],
extra_env={'JUPYTER_SERVER_ROOT': notebook_dir,
'JUPYTER_SERVER_URL': connection_url,
},
)
terminal_manager.log = app_log
base_url = webapp.settings['base_url']
handlers = [
@ -24,4 +29,4 @@ def initialize(webapp):
(ujoin(base_url, r"/api/terminals"), api_handlers.TerminalRootHandler),
(ujoin(base_url, r"/api/terminals/(\w+)"), api_handlers.TerminalHandler),
]
webapp.add_handlers(".*$", handlers)
webapp.add_handlers(".*$", handlers)

@ -1,7 +1,7 @@
// Test
casper.notebook_test(function () {
var a = 'ab\ncd';
var a = 'ab\n\ncd';
var b = 'print("b")';
var c = 'print("c")';
@ -41,6 +41,7 @@ casper.notebook_test(function () {
this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.');
this.validate_notebook_state('split', 'edit', 1);
this.select_cell(0); // Move up to cell 0
this.evaluate(function() { IPython.notebook.extend_selection('down');});
this.trigger_keydown('shift-m'); // Merge
this.validate_notebook_state('merge', 'command', 0);
this.test.assertEquals(this.get_cell_text(0), a, 'merge; Verify that cell 0 has the merged contents.');

@ -36,8 +36,8 @@ casper.notebook_test(function() {
return IPython.notebook.get_selected_cell().get_text();
});
this.test.assertEquals(output_above, 'a = 5\nprint(a)',
this.test.assertEquals(output_above, 'a = 5\n\nprint(a)',
'Successful merge_cell_above().');
this.test.assertEquals(output_below, 'a = 5\nprint(a)',
this.test.assertEquals(output_below, 'a = 5\n\nprint(a)',
'Successful merge_cell_below().');
});

@ -3,22 +3,18 @@
"version": "4.0.0",
"description": "Jupyter Notebook nodejs dependencies",
"author": "Jupyter Developers",
"license": "BSD",
"license": "BSD-3-Clause",
"repository": {
"type": "git",
"url": "https://github.com/jupyter/notebook.git"
},
"scripts": {
"bower": "bower install",
"build": "python setup.py js css"
},
"devDependencies": {
"bower": "*",
"gulp": "^3.8.11",
"gulp-less": "^3.0.2",
"gulp-livereload": "^3.8.0",
"gulp-newer": "^0.5.0",
"gulp-rename": "^1.2.2",
"gulp-sourcemaps": "^1.5.1",
"less": "~2",
"requirejs": "^2.1.17",
"source-map": "^0.4.2",
"through": "^2.3.7"
"requirejs": "^2.1.17"
}
}

@ -1,7 +0,0 @@
-e git+https://github.com/ipython/traitlets.git#egg=traitlets
-e git+https://github.com/jupyter/jupyter_core.git#egg=jupyter_core
-e git+https://github.com/jupyter/nbformat.git#egg=nbformat
-e git+https://github.com/jupyter/jupyter_client.git#egg=jupyter_client
-e git+https://github.com/ipython/ipython.git#egg=ipython
-e git+https://github.com/ipython/ipykernel.git#egg=ipykernel
-e git+https://github.com/jupyter/nbconvert.git#egg=nbconvert

@ -65,7 +65,16 @@ pjoin = os.path.join
setup_args = dict(
name = name,
description = "",
description = "A web-based notebook environment for interactive computing",
long_description = """
The Jupyter Notebook is a web application that allows you to create and
share documents that contain live code, equations, visualizations, and
explanatory text. The Notebook has support for multiple programming
languages, sharing, and interactive widgets.
Read `the documentation <https://jupyter-notebook.readthedocs.org>`_
for more information.
""",
version = version,
scripts = glob(pjoin('scripts', '*')),
packages = find_packages(),
@ -121,14 +130,7 @@ setup_args['cmdclass'] = {
# Handle scripts, dependencies, and setuptools specific things
#---------------------------------------------------------------------------
# For some commands, use setuptools. Note that we do NOT list install here!
# If you want a setuptools-enhanced install, just run 'setupegg.py install'
needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
'egg_info', 'easy_install', 'upload', 'install_egg_info',
))
if len(needs_setuptools.intersection(sys.argv)) > 0:
if any(arg.startswith('bdist') for arg in sys.argv):
import setuptools
# This dict is used for passing extra arguments that are setuptools
@ -177,6 +179,14 @@ if 'setuptools' in sys.modules:
setup_args['extras_require'] = extras_require
requires = setup_args['install_requires'] = install_requires
setup_args['entry_points'] = {
'console_scripts': [
'jupyter-notebook = notebook.notebookapp:main',
'jupyter-nbextension = notebook.nbextensions:main',
]
}
setup_args.pop('scripts', None)
#---------------------------------------------------------------------------
# Do the actual setup now
#---------------------------------------------------------------------------

@ -16,12 +16,15 @@ from __future__ import print_function
import os
import sys
import pipes
from distutils import log
from distutils.cmd import Command
from fnmatch import fnmatch
from glob import glob
from multiprocessing.pool import ThreadPool
from subprocess import check_call
#-------------------------------------------------------------------------------
# Useful globals and utility functions
#-------------------------------------------------------------------------------
@ -30,6 +33,7 @@ from subprocess import check_call
isfile = os.path.isfile
pjoin = os.path.join
repo_root = os.path.dirname(os.path.abspath(__file__))
is_repo = os.path.isdir(pjoin(repo_root, '.git'))
def oscmd(s):
print(">", s)
@ -146,11 +150,14 @@ def find_package_data():
static_data.extend([
mj('MathJax.js'),
mj('config', 'TeX-AMS_HTML-full.js'),
mj('config', 'Safe.js'),
mj('extensions', 'Safe.js'),
mj('jax', 'output', 'HTML-CSS', '*.js'),
])
for tree in [
mj('localization'), # limit to en?
mj('fonts', 'HTML-CSS', 'STIX-Web', 'woff'),
mj('extensions', 'TeX'),
mj('jax', 'input', 'TeX'),
mj('jax', 'output', 'HTML-CSS', 'autoload'),
mj('jax', 'output', 'HTML-CSS', 'fonts', 'STIX-Web'),
@ -287,6 +294,11 @@ def mtime(path):
return os.stat(path).st_mtime
def run(cmd, *args, **kwargs):
"""Echo a command before running it"""
log.info(" ".join(cmd))
return check_call(cmd, *args, **kwargs)
class Bower(Command):
description = "fetch static client-side components with bower"
@ -326,14 +338,14 @@ class Bower(Command):
if self.should_run_npm():
print("installing build dependencies with npm")
check_call(['npm', 'install'], cwd=repo_root)
run(['npm', 'install'], cwd=repo_root)
os.utime(self.node_modules, None)
env = os.environ.copy()
env['PATH'] = npm_path
try:
check_call(
run(
['bower', 'install', '--allow-root', '--config.interactive=false'],
cwd=repo_root,
env=env
@ -352,7 +364,7 @@ class CompileCSS(Command):
Regenerate the compiled CSS from LESS sources.
Requires various dev dependencies, such as gulp and lessc.
Requires various dev dependencies, such as require and lessc.
"""
description = "Recompile Notebook CSS"
user_options = []
@ -363,44 +375,98 @@ class CompileCSS(Command):
def finalize_options(self):
pass
sources = []
targets = []
for name in ('ipython', 'style'):
sources.append(pjoin(static, 'style', '%s.less' % name))
targets.append(pjoin(static, 'style', '%s.min.css' % name))
def run(self):
self.run_command('jsdeps')
env = os.environ.copy()
env['PATH'] = npm_path
try:
check_call(['gulp','css'], cwd=repo_root, env=env)
except OSError as e:
print("Failed to run gulp css: %s" % e, file=sys.stderr)
print("You can install js dependencies with `npm install`", file=sys.stderr)
raise
for src, dst in zip(self.sources, self.targets):
try:
run(['lessc',
'--source-map',
'--include-path=%s' % pipes.quote(static),
src,
dst,
], cwd=repo_root, env=env)
except OSError as e:
print("Failed to build css: %s" % e, file=sys.stderr)
print("You can install js dependencies with `npm install`", file=sys.stderr)
raise
# update package data in case this created new files
update_package_data(self.distribution)
class CompileJS(Command):
"""Rebuild minified Notebook Javascript
"""Rebuild Notebook Javascript main.min.js files
Calls `gulp js`
Calls require via build-main.js
"""
description = "Rebuild Notebook Javascript"
user_options = []
description = "Rebuild Notebook Javascript main.min.js files"
user_options = [
('force', 'f', "force rebuilding js targets"),
]
def initialize_options(self):
pass
self.force = False
def finalize_options(self):
pass
self.force = bool(self.force)
apps = ['notebook', 'tree', 'edit', 'terminal', 'auth']
targets = [ pjoin(static, app, 'js', 'main.min.js') for app in apps ]
def sources(self, name):
"""Generator yielding .js sources that an application depends on"""
yield pjoin(static, name, 'js', 'main.js')
for sec in [name, 'base', 'auth']:
for f in glob(pjoin(static, sec, 'js', '*.js')):
if not f.endswith('.min.js'):
yield f
yield pjoin(static, 'services', 'config.js')
if name == 'notebook':
for f in glob(pjoin(static, 'services', '*', '*.js')):
yield f
for parent, dirs, files in os.walk(pjoin(static, 'components')):
if os.path.basename(parent) == 'MathJax':
# don't look in MathJax, since it takes forever to walk it
dirs[:] = []
continue
for f in files:
yield pjoin(parent, f)
def should_run(self, name, target):
if self.force or not os.path.exists(target):
return True
target_mtime = mtime(target)
for source in self.sources(name):
if mtime(source) > target_mtime:
print(source, target)
return True
return False
def build_main(self, name):
"""Build main.min.js"""
target = pjoin(static, name, 'js', 'main.min.js')
if not self.should_run(name, target):
log.info("%s up to date" % target)
return
log.info("Rebuilding %s" % target)
run(['node', 'tools/build-main.js', name])
def run(self):
self.run_command('jsdeps')
env = os.environ.copy()
env['PATH'] = npm_path
try:
check_call(['gulp','js'], cwd=repo_root, env=env)
except OSError as e:
print("Failed to run gulp js: %s" % e, file=sys.stderr)
print("You can install js dependencies with `npm install`", file=sys.stderr)
raise
pool = ThreadPool()
pool.map(self.build_main, self.apps)
# update package data in case this created new files
update_package_data(self.distribution)
@ -437,20 +503,44 @@ def css_js_prerelease(command, strict=False):
def run(self):
self.distribution.run_command('jsversion')
jsdeps = self.distribution.get_command_obj('jsdeps')
jsdeps.force = True
js = self.distribution.get_command_obj('js')
js.force = True
css = self.distribution.get_command_obj('css')
css.force = True
jsdeps.force = js.force = strict
targets = [ jsdeps.bower_dir ]
targets.extend(js.targets)
targets.extend(css.targets)
missing = [ t for t in targets if not os.path.exists(t) ]
if not is_repo and not missing:
# If we're an sdist, we aren't a repo and everything should be present.
# Don't rebuild js/css in that case.
command.run(self)
return
try:
self.distribution.run_command('css')
self.distribution.run_command('js')
except Exception as e:
if strict:
log.warn("rebuilding js and css failed")
# refresh missing
missing = [ t for t in targets if not os.path.exists(t) ]
if strict or missing:
# die if strict or any targets didn't build
prefix = os.path.commonprefix([repo_root + os.sep] + missing)
missing = [ m[len(prefix):] for m in missing ]
log.warn("rebuilding js and css failed. The following required files are missing: %s" % missing)
raise e
else:
log.warn("rebuilding js and css failed (not a problem)")
log.warn(str(e))
# check again for missing targets, just in case:
missing = [ t for t in targets if not os.path.exists(t) ]
if missing:
# command succeeded, but targets still missing (?!)
prefix = os.path.commonprefix([repo_root + os.sep] + missing)
missing = [ m[len(prefix):] for m in missing ]
raise ValueError("The following required files are missing: %s" % missing)
command.run(self)
return DecoratedCommand

Loading…
Cancel
Save