├── .gitignore ├── COPYING ├── Default.sublime-commands ├── Default.sublime-keymap ├── Main.sublime-menu ├── Python2.tmLanguage ├── README.md ├── SublimeIPythonNotebook.sublime-settings ├── SublimeIPythonNotebook.tmLanguage ├── SublimeIPythonNotebook.tmLanguage.JSON ├── TODO.md ├── external ├── __init__.py ├── copy_ipython_subset.sh ├── nbformat │ ├── COPYING.txt │ ├── __init__.py │ ├── data.py │ ├── encoding.py │ ├── ipstruct.py │ ├── nbbase.py │ ├── nbjson.py │ ├── nbpy.py │ ├── py3compat.py │ └── rwbase.py ├── nbformat3 │ ├── COPYING.txt │ ├── __init__.py │ ├── data.py │ ├── encoding.py │ ├── ipstruct.py │ ├── nbbase.py │ ├── nbjson.py │ ├── nbpy.py │ ├── py3compat.py │ └── rwbase.py └── websocket │ ├── LICENSE │ ├── __init__.py │ └── websocket3.py ├── ipy_connection.py ├── ipy_view.py ├── ipynb.hidden-tmTheme ├── ipynb_dark.hidden-tmTheme ├── ipynb_light.hidden-tmTheme └── subl_ipy_notebook.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.bak 3 | *.cache 4 | .DS_Store 5 | .idea -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { "caption": "Open IPython Notebook", "command": "inb_prompt_list_notebooks" }, 3 | { "caption": "Save IPython Notebook", "command": "inb_save_notebook" }, 4 | { "caption": "Restart IPython Notebook Kernel", "command": "inb_restart_kernel" }, 5 | { "caption": "Interrupt IPython Notebook Kernel", "command": "inb_interrupt_kernel" }, 6 | { "caption": "Shutdown IPython Notebook Kernel", "command": "inb_shutdown_kernel" }, 7 | { "caption": "Open Current Notebook As Ipynb File", "command": "inb_open_as_ipynb" }, 8 | { "caption": "Rename IPython Notebook", "command": "inb_rename_notebook" } 9 | ] 10 | -------------------------------------------------------------------------------- /Default.sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": ["shift+enter"], "command": "inb_run_in_notebook", "args": {"inplace" : false}, 4 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 5 | }, 6 | { 7 | "keys": ["ctrl+enter"], "command": "inb_run_in_notebook", "args": {"inplace" : true}, 8 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 9 | }, 10 | { 11 | "keys": ["backspace"], "command": "inb_backspace", 12 | "context": 13 | [ 14 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 15 | { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true } 16 | ] 17 | }, 18 | { 19 | "keys": ["super+s"], "command": "inb_save_notebook", 20 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 21 | }, 22 | { 23 | "keys": ["ctrl+s"], "command": "inb_save_notebook", 24 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 25 | }, 26 | { 27 | "keys": ["ctrl+m", "d"], "command": "inb_delete_current_cell", 28 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 29 | }, 30 | { 31 | "keys": ["ctrl+m", "a"], "command": "inb_insert_cell_above", 32 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 33 | }, 34 | { 35 | "keys": ["ctrl+m", "b"], "command": "inb_insert_cell_below", 36 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 37 | }, 38 | { 39 | "keys": ["ctrl+m", "y"], "command": "inb_change_cell_type", "args": {"new_type" : "code"}, 40 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 41 | }, 42 | { 43 | "keys": ["ctrl+m", "m"], "command": "inb_change_cell_type", "args": {"new_type" : "markdown"}, 44 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 45 | }, 46 | { 47 | "keys": ["ctrl+m", "t"], "command": "inb_change_cell_type", "args": {"new_type" : "raw"}, 48 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 49 | }, 50 | { 51 | "keys": ["ctrl+m", "s"], "command": "inb_save_notebook", 52 | "context" : [ { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }] 53 | }, 54 | { 55 | "keys": ["up"], "command": "inb_move_up", 56 | "context" : [ 57 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 58 | { "key": "auto_complete_visible", "operator": "equal", "operand": false } 59 | ] 60 | }, 61 | { 62 | "keys": ["ctrl+up"], "command": "inb_move_to_cell", "args": {"up" : true}, 63 | "context" : [ 64 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 65 | { "key": "auto_complete_visible", "operator": "equal", "operand": false } 66 | ] 67 | }, 68 | { 69 | "keys": ["ctrl+down"], "command": "inb_move_to_cell", "args": {"up" : false}, 70 | "context" : [ 71 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 72 | { "key": "auto_complete_visible", "operator": "equal", "operand": false } 73 | ] 74 | }, 75 | { 76 | "keys": ["ctrl+m", "p"], "command": "inb_move_to_cell", "args": {"up" : true}, 77 | "context" : [ 78 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 79 | { "key": "auto_complete_visible", "operator": "equal", "operand": false } 80 | ] 81 | }, 82 | { 83 | "keys": ["ctrl+m", "n"], "command": "inb_move_to_cell", "args": {"up" : false}, 84 | "context" : [ 85 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 86 | { "key": "auto_complete_visible", "operator": "equal", "operand": false } 87 | ] 88 | }, 89 | { 90 | "keys": ["down"], "command": "inb_move_down", 91 | "context" : [ 92 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 93 | { "key": "auto_complete_visible", "operator": "equal", "operand": false } 94 | ] 95 | }, 96 | { 97 | "keys": ["left"], "command": "inb_move_left", 98 | "context" : [ 99 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 100 | { "key": "auto_complete_visible", "operator": "equal", "operand": false } 101 | ] 102 | }, 103 | { 104 | "keys": ["right"], "command": "inb_move_right", 105 | "context" : [ 106 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 107 | { "key": "auto_complete_visible", "operator": "equal", "operand": false } 108 | ] 109 | } 110 | 111 | ] 112 | 113 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "IPython Notebook", 16 | "children": 17 | [ 18 | { 19 | "command": "open_file", 20 | "args": {"file": "${packages}/IPython Notebook/README.md"}, 21 | "caption": "README" 22 | }, 23 | { "caption": "-" }, 24 | { 25 | "command": "open_file", 26 | "args": {"file": "${packages}/IPython Notebook/SublimeIPythonNotebook.sublime-settings"}, 27 | "caption": "Settings – Default" 28 | }, 29 | { 30 | "command": "open_file", 31 | "args": {"file": "${packages}/User/SublimeIPythonNotebook.sublime-settings"}, 32 | "caption": "Settings – User" 33 | }, 34 | { "caption": "-" }, 35 | { 36 | "command": "open_file", 37 | "args": {"file": "${packages}/IPython Notebook/Default.sublime-keymap"}, 38 | "caption": "Key Bindings – Default" 39 | }, 40 | { 41 | "command": "open_file", 42 | "args": {"file": "${packages}/User/Default (OSX).sublime-keymap",}, 43 | "caption": "Key Bindings – User" 44 | }, 45 | { "caption": "-" } 46 | ] 47 | } 48 | ] 49 | } 50 | ] 51 | } 52 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sublime IPython Notebook 2 | This is a Sublime Text 3 plugin that emulates IPython notebook interface inside Sublime. 3 | 4 | __NOTE: this plugin [does not work with the latest versions of Ipython Notebook!](https://github.com/maximsch2/SublimeIPythonNotebook/issues/25#issuecomment-51663193) (2.0 or greater)__ 5 | 6 | ## Disclaimer 7 | While the plugin looks stable so far and I am trying to preserve as much of the notebook data as possible, there are no guarantees that you data will be safe. Do not use it for the notebooks that contain valuable data without doing a backup. 8 | 9 | ## How to use 10 | 1. Connect to the notebook server using "Open IPython Notebook" command. Choose a notebook you want to open and it will open in a separate buffer. 11 | 2. I am trying to support keyboard shortcuts from the web version of the notebook. Currently you can use: 12 | - shift+enter - execute current cell 13 | - ctrl+enter - execute current cell inplace 14 | - ctrl+m, d - delete current cell 15 | - ctrl+m, a - add cell above current 16 | - ctrl+m, b - add cell below current 17 | - ctrl+m, n - select next cell 18 | - ctlr+m, p - select previous cell 19 | - ctrl+m, y - code cell 20 | - ctrl+m, m - markdown cell 21 | - ctrl+m, t - raw cell 22 | - ctrl+m, s - save notebook (ctrl+s and super+s will work too) 23 | 24 | ## Notes 25 | 1. You can use %pylab inline. You will not be able to see the plots, but they will be saved in the notebook and available when viewing it through the web interface. 26 | 2. I am using websocket-client library from https://github.com/liris/websocket-client and (slightly patched) subset of the IPython. You do not have to install them separately. 27 | 3. ST3 port was contributed by [chirswl](https://github.com/chriswl) 28 | 4. Dark theme, support for password-protected servers and nicer last-used-server picker was contributed by [z-m-k](https://github.com/z-m-k) 29 | 30 | ## Vintage Mode 31 | In Vintage mode, for the navigation keys to work as expected in IPython Notebook buffer, you need to modify some keybindings. Add the following to your `Key Bindings - User`. 32 | 33 | 1. Add a `context key` to `Shift+Enter` so you can run a cell with `Shift+Enter` in the command mode: 34 | 35 | ``` 36 | { "keys": ["shift+enter"], "command": "set_motion", "args": { 37 | "motion": "move", 38 | "motion_args": {"by": "lines", "forward": true, "extend": true }}, 39 | "context": [ 40 | { "key": "setting.command_mode"}, 41 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": false }, 42 | ] 43 | }, 44 | ``` 45 | 2. Command mode Up/Down navigation keys: 46 | 47 | ``` 48 | { "keys": ["j"], "command": "set_motion", "args": { 49 | "motion": "move", 50 | "motion_args": {"by": "lines", "forward": true, "extend": true }, 51 | "linewise": true }, 52 | "context": [ 53 | { "key": "setting.command_mode"}, 54 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": false }, 55 | ] 56 | }, 57 | 58 | { 59 | "keys": ["j"], "command": "inb_move_up", 60 | "context" : [ 61 | { "key": "setting.command_mode"} 62 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 63 | { "key": "auto_complete_visible", "operator": "equal", "operand": false }, 64 | ] 65 | }, 66 | 67 | { "keys": ["k"], "command": "set_motion", "args": { 68 | "motion": "move", 69 | "motion_args": {"by": "lines", "forward": false, "extend": true }, 70 | "linewise": true }, 71 | "context": [ 72 | { "key": "setting.command_mode"}, 73 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": false }, 74 | ] 75 | }, 76 | 77 | { 78 | "keys": ["k"], "command": "inb_move_down", 79 | "context" : [ 80 | { "key": "setting.command_mode"}, 81 | { "key": "setting.ipython_notebook", "operator": "equal", "operand": true }, 82 | { "key": "auto_complete_visible", "operator": "equal", "operand": false }, 83 | ] 84 | }, 85 | ``` 86 | -------------------------------------------------------------------------------- /SublimeIPythonNotebook.sublime-settings: -------------------------------------------------------------------------------- 1 | // Default SublimeIPythonNotebook Preferences file 2 | // 3 | // DO NOT EDIT THIS FILE! Copy it to your Packages/User folder and modify that copy. 4 | // 5 | 6 | { 7 | //Color scheme for displaying notebooks 8 | //Light: 9 | "color_scheme": "Packages/IPython Notebook/ipynb_light.hidden-tmTheme", 10 | //Dark: 11 | //"color_scheme": "Packages/IPython Notebook/ipynb_dark.hidden-tmTheme", 12 | } 13 | -------------------------------------------------------------------------------- /SublimeIPythonNotebook.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | ipynb 8 | 9 | foldingStartMarker 10 | \#Output\[.*\] 11 | foldingStopMarker 12 | \#\/Output 13 | name 14 | IPython Notebook 15 | patterns 16 | 17 | 18 | begin 19 | \#Input-R\[.*\] 20 | 21 | beginCaptures 22 | 23 | 0 24 | 25 | name 26 | comment 27 | 28 | 29 | contentName 30 | ipynb.source.input.r source.r 31 | end 32 | \#\/Input 33 | endCaptures 34 | 35 | 0 36 | 37 | name 38 | comment 39 | 40 | 41 | patterns 42 | 43 | 44 | include 45 | source.r 46 | 47 | 48 | 49 | 50 | begin 51 | \#Markdown 52 | 53 | beginCaptures 54 | 55 | 0 56 | 57 | name 58 | comment 59 | 60 | 61 | contentName 62 | ipynb.text.tex.latex text.tex.latex 63 | end 64 | \#\/Markdown 65 | endCaptures 66 | 67 | 0 68 | 69 | name 70 | comment 71 | 72 | 73 | patterns 74 | 75 | 76 | include 77 | text.tex.latex 78 | 79 | 80 | 81 | 82 | begin 83 | \#Input\[(.*)\]\n 84 | beginCaptures 85 | 86 | 0 87 | 88 | name 89 | comment 90 | 91 | 92 | contentName 93 | ipynb.source.input.python source.python 94 | end 95 | (\#\/Input\[\1\])$ 96 | endCaptures 97 | 98 | 0 99 | 100 | name 101 | comment 102 | 103 | 104 | patterns 105 | 106 | 107 | include 108 | #ipynb_input_python 109 | 110 | 111 | 112 | 113 | begin 114 | \#Output\[.*\] 115 | 116 | beginCaptures 117 | 118 | 0 119 | 120 | name 121 | ipynb.source.invisible 122 | 123 | 124 | contentName 125 | ipynb.source.output 126 | end 127 | \#\/Output 128 | endCaptures 129 | 130 | 0 131 | 132 | name 133 | ipynb.source.invisible 134 | 135 | 136 | 137 | 138 | repository 139 | 140 | ipynb_input_python 141 | 142 | patterns 143 | 144 | 145 | include 146 | source.python_no_brackets 147 | 148 | 149 | 150 | 151 | scopeName 152 | source.ipynb 153 | uuid 154 | a09ea990-df95-11e2-a28f-0800200c9a66 155 | 156 | 157 | -------------------------------------------------------------------------------- /SublimeIPythonNotebook.tmLanguage.JSON: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": ["ipynb"], 3 | "name": "IPython Notebook", 4 | "scopeName": "source.ipynb", 5 | "uuid": "a09ea990-df95-11e2-a28f-0800200c9a66", 6 | "foldingStartMarker" : "\\#Output\\[.*\\]", 7 | "foldingStopMarker" : "\\#\\/Output", 8 | "patterns": [ 9 | // { 10 | // "match": "Input\\[.*\\]", 11 | // "name": "keyword.source.python", 12 | // "comment": "Beginning of cell input" 13 | // }, 14 | 15 | { 16 | 17 | "contentName": "ipynb.source.input.r source.r", 18 | "begin": "\\#Input-R\\[.*\\]\n", 19 | "end": "\\#\\/Input", 20 | "beginCaptures": { 21 | "0": { "name": "comment"} 22 | }, 23 | "endCaptures": { 24 | "0": { "name": "comment"} 25 | }, 26 | "patterns": [ 27 | { 28 | "include": "source.r" 29 | }, 30 | ] 31 | }, 32 | 33 | { 34 | 35 | "contentName": "ipynb.text.tex.latex text.tex.latex", 36 | "begin": "\\#Markdown\n", 37 | "end": "\\#\\/Markdown", 38 | "beginCaptures": { 39 | "0": { "name": "comment"} 40 | }, 41 | "endCaptures": { 42 | "0": { "name": "comment"} 43 | }, 44 | "patterns": [ 45 | { 46 | "include": "text.tex.latex" 47 | }, 48 | ] 49 | }, 50 | 51 | 52 | { 53 | "contentName": "ipynb.source.input.python source.python", 54 | "begin": "\\#Input\\[(.*)\\]\\n", 55 | "end": "(\\#\\/Input\\[\\1\\])$", 56 | "patterns": [ 57 | { 58 | "include": "#ipynb_input_python" 59 | } 60 | ], 61 | 62 | "beginCaptures": { 63 | "0": { "name": "comment"} 64 | }, 65 | "endCaptures": { 66 | "0": { "name": "comment"} 67 | }, 68 | 69 | }, 70 | 71 | { 72 | "contentName": "ipynb.source.output", 73 | //"name": "storage.type.string.python", 74 | "begin": "\\#Output\\[.*\\]\n", 75 | "end": "\\#\\/Output", 76 | "beginCaptures": { 77 | "0": { "name": "ipynb.source.invisible"} 78 | }, 79 | "endCaptures": { 80 | "0": { "name": "ipynb.source.invisible"} 81 | }, 82 | 83 | }, 84 | ], 85 | "repository" : { 86 | "ipynb_input_python" : { 87 | "patterns" : [ 88 | {"include" : "source.python_no_brackets"} 89 | ] 90 | } 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | - Alert if notebook was changed and offer to save before closing tab 2 | - Better control for scrolling: if I have large ouput in the last cell that suddenly gets replaced, then my scroll position is screwed up 3 | - Maybe shuold keep scroll position fixed while changing output! 4 | - Unclosed parenthesis still break highlighting (""" for python, and ' + " for R cells) 5 | - Initial scroll position is bad for empty notebooks 6 | - Support set_next_input 7 | - Add an option of saving a backup copy of notebook json file (use git to have all copies?): 8 | - For now it is possible to use inb_open_as_ipynb command 9 | - Support image preview in some external program 10 | 11 | BUGS: 12 | 13 | Wrong highlighting for open """ . 14 | 15 | TODO for IPython 1.0 16 | 17 | - support stdin input for %debug, raw_input and so on 18 | -------------------------------------------------------------------------------- /external/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximsch2/SublimeIPythonNotebook/8b383eba4bdba32e963ec2a0a054f6870bfe6908/external/__init__.py -------------------------------------------------------------------------------- /external/copy_ipython_subset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | IPYROOT=$1 4 | IPYDIR=$IPYROOT/IPython 5 | 6 | rm -rf nbformat 7 | mkdir nbformat 8 | cp $IPYROOT/COPYING.txt nbformat/ 9 | 10 | cp -R $IPYDIR/nbformat/v3/*.py nbformat/ 11 | rm -f nbformat/convert.py 12 | rm -f nbformat/validator.py 13 | sed -i bak "/convert/d" nbformat/__init__.py 14 | cp $IPYDIR/utils/ipstruct.py nbformat/ 15 | cp $IPYDIR/utils/data.py nbformat/ 16 | cp $IPYDIR/utils/py3compat.py nbformat/ 17 | cp $IPYDIR/utils/encoding.py nbformat/ 18 | sed -i bak "s/IPython.utils//" nbformat/ipstruct.py 19 | sed -i bak "s/IPython.utils//" nbformat/nbbase.py 20 | sed -i bak "s/IPython.utils/./" nbformat/*.py 21 | rm -f nbformat/*.pybak 22 | 23 | cp nbformat/* nbformat3/ 24 | 2to3 -w nbformat3/*.py 25 | 26 | -------------------------------------------------------------------------------- /external/nbformat/COPYING.txt: -------------------------------------------------------------------------------- 1 | ============================= 2 | The IPython licensing terms 3 | ============================= 4 | 5 | IPython is licensed under the terms of the Modified BSD License (also known as 6 | New or Revised BSD), as follows: 7 | 8 | Copyright (c) 2008-2010, IPython Development Team 9 | Copyright (c) 2001-2007, Fernando Perez. 10 | Copyright (c) 2001, Janko Hauser 11 | Copyright (c) 2001, Nathaniel Gray 12 | 13 | All rights reserved. 14 | 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions are met: 17 | 18 | Redistributions of source code must retain the above copyright notice, this 19 | list of conditions and the following disclaimer. 20 | 21 | Redistributions in binary form must reproduce the above copyright notice, this 22 | list of conditions and the following disclaimer in the documentation and/or 23 | other materials provided with the distribution. 24 | 25 | Neither the name of the IPython Development Team nor the names of its 26 | contributors may be used to endorse or promote products derived from this 27 | software without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 30 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 31 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 33 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 36 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 37 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | 40 | About the IPython Development Team 41 | ---------------------------------- 42 | 43 | Fernando Perez began IPython in 2001 based on code from Janko Hauser 44 | and Nathaniel Gray . Fernando is still 45 | the project lead. 46 | 47 | The IPython Development Team is the set of all contributors to the IPython 48 | project. This includes all of the IPython subprojects. A full list with 49 | details is kept in the documentation directory, in the file 50 | ``about/credits.txt``. 51 | 52 | The core team that coordinates development on GitHub can be found here: 53 | http://github.com/ipython. As of late 2010, it consists of: 54 | 55 | * Brian E. Granger 56 | * Jonathan March 57 | * Evan Patterson 58 | * Fernando Perez 59 | * Min Ragan-Kelley 60 | * Robert Kern 61 | 62 | 63 | Our Copyright Policy 64 | -------------------- 65 | 66 | IPython uses a shared copyright model. Each contributor maintains copyright 67 | over their contributions to IPython. But, it is important to note that these 68 | contributions are typically only changes to the repositories. Thus, the IPython 69 | source code, in its entirety is not the copyright of any single person or 70 | institution. Instead, it is the collective copyright of the entire IPython 71 | Development Team. If individual contributors want to maintain a record of what 72 | changes/contributions they have specific copyright on, they should indicate 73 | their copyright in the commit message of the change, when they commit the 74 | change to one of the IPython repositories. 75 | 76 | With this in mind, the following banner should be used in any source code file 77 | to indicate the copyright and license terms: 78 | 79 | #----------------------------------------------------------------------------- 80 | # Copyright (c) 2010, IPython Development Team. 81 | # 82 | # Distributed under the terms of the Modified BSD License. 83 | # 84 | # The full license is in the file COPYING.txt, distributed with this software. 85 | #----------------------------------------------------------------------------- 86 | -------------------------------------------------------------------------------- /external/nbformat/__init__.py: -------------------------------------------------------------------------------- 1 | """The main API for the v3 notebook format. 2 | 3 | Authors: 4 | 5 | * Brian Granger 6 | """ 7 | 8 | #----------------------------------------------------------------------------- 9 | # Copyright (C) 2008-2011 The IPython Development Team 10 | # 11 | # Distributed under the terms of the BSD License. The full license is in 12 | # the file COPYING, distributed as part of this software. 13 | #----------------------------------------------------------------------------- 14 | 15 | #----------------------------------------------------------------------------- 16 | # Imports 17 | #----------------------------------------------------------------------------- 18 | 19 | from .nbbase import ( 20 | NotebookNode, 21 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, 22 | new_metadata, new_author, new_heading_cell, nbformat, nbformat_minor 23 | ) 24 | 25 | from .nbjson import reads as reads_json, writes as writes_json 26 | from .nbjson import reads as read_json, writes as write_json 27 | from .nbjson import to_notebook as to_notebook_json 28 | 29 | from .nbpy import reads as reads_py, writes as writes_py 30 | from .nbpy import reads as read_py, writes as write_py 31 | from .nbpy import to_notebook as to_notebook_py 32 | 33 | 34 | #----------------------------------------------------------------------------- 35 | # Code 36 | #----------------------------------------------------------------------------- 37 | 38 | def parse_filename(fname): 39 | """Parse a notebook filename. 40 | 41 | This function takes a notebook filename and returns the notebook 42 | format (json/py) and the notebook name. This logic can be 43 | summarized as follows: 44 | 45 | * notebook.ipynb -> (notebook.ipynb, notebook, json) 46 | * notebook.json -> (notebook.json, notebook, json) 47 | * notebook.py -> (notebook.py, notebook, py) 48 | * notebook -> (notebook.ipynb, notebook, json) 49 | 50 | Parameters 51 | ---------- 52 | fname : unicode 53 | The notebook filename. The filename can use a specific filename 54 | extention (.ipynb, .json, .py) or none, in which case .ipynb will 55 | be assumed. 56 | 57 | Returns 58 | ------- 59 | (fname, name, format) : (unicode, unicode, unicode) 60 | The filename, notebook name and format. 61 | """ 62 | if fname.endswith(u'.ipynb'): 63 | format = u'json' 64 | elif fname.endswith(u'.json'): 65 | format = u'json' 66 | elif fname.endswith(u'.py'): 67 | format = u'py' 68 | else: 69 | fname = fname + u'.ipynb' 70 | format = u'json' 71 | name = fname.split('.')[0] 72 | return fname, name, format 73 | 74 | -------------------------------------------------------------------------------- /external/nbformat/data.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """Utilities for working with data structures like lists, dicts and tuples. 3 | """ 4 | 5 | #----------------------------------------------------------------------------- 6 | # Copyright (C) 2008-2011 The IPython Development Team 7 | # 8 | # Distributed under the terms of the BSD License. The full license is in 9 | # the file COPYING, distributed as part of this software. 10 | #----------------------------------------------------------------------------- 11 | 12 | def uniq_stable(elems): 13 | """uniq_stable(elems) -> list 14 | 15 | Return from an iterable, a list of all the unique elements in the input, 16 | but maintaining the order in which they first appear. 17 | 18 | Note: All elements in the input must be hashable for this routine 19 | to work, as it internally uses a set for efficiency reasons. 20 | """ 21 | seen = set() 22 | return [x for x in elems if x not in seen and not seen.add(x)] 23 | 24 | 25 | def flatten(seq): 26 | """Flatten a list of lists (NOT recursive, only works for 2d lists).""" 27 | 28 | return [x for subseq in seq for x in subseq] 29 | 30 | 31 | def chop(seq, size): 32 | """Chop a sequence into chunks of the given size.""" 33 | return [seq[i:i+size] for i in xrange(0,len(seq),size)] 34 | 35 | 36 | -------------------------------------------------------------------------------- /external/nbformat/encoding.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Utilities for dealing with text encodings 4 | """ 5 | 6 | #----------------------------------------------------------------------------- 7 | # Copyright (C) 2008-2012 The IPython Development Team 8 | # 9 | # Distributed under the terms of the BSD License. The full license is in 10 | # the file COPYING, distributed as part of this software. 11 | #----------------------------------------------------------------------------- 12 | 13 | #----------------------------------------------------------------------------- 14 | # Imports 15 | #----------------------------------------------------------------------------- 16 | import sys 17 | import locale 18 | 19 | # to deal with the possibility of sys.std* not being a stream at all 20 | def get_stream_enc(stream, default=None): 21 | """Return the given stream's encoding or a default. 22 | 23 | There are cases where ``sys.std*`` might not actually be a stream, so 24 | check for the encoding attribute prior to returning it, and return 25 | a default if it doesn't exist or evaluates as False. ``default`` 26 | is None if not provided. 27 | """ 28 | if not hasattr(stream, 'encoding') or not stream.encoding: 29 | return default 30 | else: 31 | return stream.encoding 32 | 33 | # Less conservative replacement for sys.getdefaultencoding, that will try 34 | # to match the environment. 35 | # Defined here as central function, so if we find better choices, we 36 | # won't need to make changes all over IPython. 37 | def getdefaultencoding(): 38 | """Return IPython's guess for the default encoding for bytes as text. 39 | 40 | Asks for stdin.encoding first, to match the calling Terminal, but that 41 | is often None for subprocesses. Fall back on locale.getpreferredencoding() 42 | which should be a sensible platform default (that respects LANG environment), 43 | and finally to sys.getdefaultencoding() which is the most conservative option, 44 | and usually ASCII. 45 | """ 46 | enc = get_stream_enc(sys.stdin) 47 | if not enc or enc=='ascii': 48 | try: 49 | # There are reports of getpreferredencoding raising errors 50 | # in some cases, which may well be fixed, but let's be conservative here. 51 | enc = locale.getpreferredencoding() 52 | except Exception: 53 | pass 54 | return enc or sys.getdefaultencoding() 55 | 56 | DEFAULT_ENCODING = getdefaultencoding() 57 | -------------------------------------------------------------------------------- /external/nbformat/ipstruct.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """A dict subclass that supports attribute style access. 3 | 4 | Authors: 5 | 6 | * Fernando Perez (original) 7 | * Brian Granger (refactoring to a dict subclass) 8 | """ 9 | 10 | #----------------------------------------------------------------------------- 11 | # Copyright (C) 2008-2011 The IPython Development Team 12 | # 13 | # Distributed under the terms of the BSD License. The full license is in 14 | # the file COPYING, distributed as part of this software. 15 | #----------------------------------------------------------------------------- 16 | 17 | #----------------------------------------------------------------------------- 18 | # Imports 19 | #----------------------------------------------------------------------------- 20 | 21 | __all__ = ['Struct'] 22 | 23 | #----------------------------------------------------------------------------- 24 | # Code 25 | #----------------------------------------------------------------------------- 26 | 27 | 28 | class Struct(dict): 29 | """A dict subclass with attribute style access. 30 | 31 | This dict subclass has a a few extra features: 32 | 33 | * Attribute style access. 34 | * Protection of class members (like keys, items) when using attribute 35 | style access. 36 | * The ability to restrict assignment to only existing keys. 37 | * Intelligent merging. 38 | * Overloaded operators. 39 | """ 40 | _allownew = True 41 | def __init__(self, *args, **kw): 42 | """Initialize with a dictionary, another Struct, or data. 43 | 44 | Parameters 45 | ---------- 46 | args : dict, Struct 47 | Initialize with one dict or Struct 48 | kw : dict 49 | Initialize with key, value pairs. 50 | 51 | Examples 52 | -------- 53 | 54 | >>> s = Struct(a=10,b=30) 55 | >>> s.a 56 | 10 57 | >>> s.b 58 | 30 59 | >>> s2 = Struct(s,c=30) 60 | >>> sorted(s2.keys()) 61 | ['a', 'b', 'c'] 62 | """ 63 | object.__setattr__(self, '_allownew', True) 64 | dict.__init__(self, *args, **kw) 65 | 66 | def __setitem__(self, key, value): 67 | """Set an item with check for allownew. 68 | 69 | Examples 70 | -------- 71 | 72 | >>> s = Struct() 73 | >>> s['a'] = 10 74 | >>> s.allow_new_attr(False) 75 | >>> s['a'] = 10 76 | >>> s['a'] 77 | 10 78 | >>> try: 79 | ... s['b'] = 20 80 | ... except KeyError: 81 | ... print 'this is not allowed' 82 | ... 83 | this is not allowed 84 | """ 85 | if not self._allownew and key not in self: 86 | raise KeyError( 87 | "can't create new attribute %s when allow_new_attr(False)" % key) 88 | dict.__setitem__(self, key, value) 89 | 90 | def __setattr__(self, key, value): 91 | """Set an attr with protection of class members. 92 | 93 | This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to 94 | :exc:`AttributeError`. 95 | 96 | Examples 97 | -------- 98 | 99 | >>> s = Struct() 100 | >>> s.a = 10 101 | >>> s.a 102 | 10 103 | >>> try: 104 | ... s.get = 10 105 | ... except AttributeError: 106 | ... print "you can't set a class member" 107 | ... 108 | you can't set a class member 109 | """ 110 | # If key is an str it might be a class member or instance var 111 | if isinstance(key, str): 112 | # I can't simply call hasattr here because it calls getattr, which 113 | # calls self.__getattr__, which returns True for keys in 114 | # self._data. But I only want keys in the class and in 115 | # self.__dict__ 116 | if key in self.__dict__ or hasattr(Struct, key): 117 | raise AttributeError( 118 | 'attr %s is a protected member of class Struct.' % key 119 | ) 120 | try: 121 | self.__setitem__(key, value) 122 | except KeyError as e: 123 | raise AttributeError(e) 124 | 125 | def __getattr__(self, key): 126 | """Get an attr by calling :meth:`dict.__getitem__`. 127 | 128 | Like :meth:`__setattr__`, this method converts :exc:`KeyError` to 129 | :exc:`AttributeError`. 130 | 131 | Examples 132 | -------- 133 | 134 | >>> s = Struct(a=10) 135 | >>> s.a 136 | 10 137 | >>> type(s.get) 138 | <... 'builtin_function_or_method'> 139 | >>> try: 140 | ... s.b 141 | ... except AttributeError: 142 | ... print "I don't have that key" 143 | ... 144 | I don't have that key 145 | """ 146 | try: 147 | result = self[key] 148 | except KeyError: 149 | raise AttributeError(key) 150 | else: 151 | return result 152 | 153 | def __iadd__(self, other): 154 | """s += s2 is a shorthand for s.merge(s2). 155 | 156 | Examples 157 | -------- 158 | 159 | >>> s = Struct(a=10,b=30) 160 | >>> s2 = Struct(a=20,c=40) 161 | >>> s += s2 162 | >>> sorted(s.keys()) 163 | ['a', 'b', 'c'] 164 | """ 165 | self.merge(other) 166 | return self 167 | 168 | def __add__(self,other): 169 | """s + s2 -> New Struct made from s.merge(s2). 170 | 171 | Examples 172 | -------- 173 | 174 | >>> s1 = Struct(a=10,b=30) 175 | >>> s2 = Struct(a=20,c=40) 176 | >>> s = s1 + s2 177 | >>> sorted(s.keys()) 178 | ['a', 'b', 'c'] 179 | """ 180 | sout = self.copy() 181 | sout.merge(other) 182 | return sout 183 | 184 | def __sub__(self,other): 185 | """s1 - s2 -> remove keys in s2 from s1. 186 | 187 | Examples 188 | -------- 189 | 190 | >>> s1 = Struct(a=10,b=30) 191 | >>> s2 = Struct(a=40) 192 | >>> s = s1 - s2 193 | >>> s 194 | {'b': 30} 195 | """ 196 | sout = self.copy() 197 | sout -= other 198 | return sout 199 | 200 | def __isub__(self,other): 201 | """Inplace remove keys from self that are in other. 202 | 203 | Examples 204 | -------- 205 | 206 | >>> s1 = Struct(a=10,b=30) 207 | >>> s2 = Struct(a=40) 208 | >>> s1 -= s2 209 | >>> s1 210 | {'b': 30} 211 | """ 212 | for k in other.keys(): 213 | if k in self: 214 | del self[k] 215 | return self 216 | 217 | def __dict_invert(self, data): 218 | """Helper function for merge. 219 | 220 | Takes a dictionary whose values are lists and returns a dict with 221 | the elements of each list as keys and the original keys as values. 222 | """ 223 | outdict = {} 224 | for k,lst in data.items(): 225 | if isinstance(lst, str): 226 | lst = lst.split() 227 | for entry in lst: 228 | outdict[entry] = k 229 | return outdict 230 | 231 | def dict(self): 232 | return self 233 | 234 | def copy(self): 235 | """Return a copy as a Struct. 236 | 237 | Examples 238 | -------- 239 | 240 | >>> s = Struct(a=10,b=30) 241 | >>> s2 = s.copy() 242 | >>> type(s2) is Struct 243 | True 244 | """ 245 | return Struct(dict.copy(self)) 246 | 247 | def hasattr(self, key): 248 | """hasattr function available as a method. 249 | 250 | Implemented like has_key. 251 | 252 | Examples 253 | -------- 254 | 255 | >>> s = Struct(a=10) 256 | >>> s.hasattr('a') 257 | True 258 | >>> s.hasattr('b') 259 | False 260 | >>> s.hasattr('get') 261 | False 262 | """ 263 | return key in self 264 | 265 | def allow_new_attr(self, allow = True): 266 | """Set whether new attributes can be created in this Struct. 267 | 268 | This can be used to catch typos by verifying that the attribute user 269 | tries to change already exists in this Struct. 270 | """ 271 | object.__setattr__(self, '_allownew', allow) 272 | 273 | def merge(self, __loc_data__=None, __conflict_solve=None, **kw): 274 | """Merge two Structs with customizable conflict resolution. 275 | 276 | This is similar to :meth:`update`, but much more flexible. First, a 277 | dict is made from data+key=value pairs. When merging this dict with 278 | the Struct S, the optional dictionary 'conflict' is used to decide 279 | what to do. 280 | 281 | If conflict is not given, the default behavior is to preserve any keys 282 | with their current value (the opposite of the :meth:`update` method's 283 | behavior). 284 | 285 | Parameters 286 | ---------- 287 | __loc_data : dict, Struct 288 | The data to merge into self 289 | __conflict_solve : dict 290 | The conflict policy dict. The keys are binary functions used to 291 | resolve the conflict and the values are lists of strings naming 292 | the keys the conflict resolution function applies to. Instead of 293 | a list of strings a space separated string can be used, like 294 | 'a b c'. 295 | kw : dict 296 | Additional key, value pairs to merge in 297 | 298 | Notes 299 | ----- 300 | 301 | The `__conflict_solve` dict is a dictionary of binary functions which will be used to 302 | solve key conflicts. Here is an example:: 303 | 304 | __conflict_solve = dict( 305 | func1=['a','b','c'], 306 | func2=['d','e'] 307 | ) 308 | 309 | In this case, the function :func:`func1` will be used to resolve 310 | keys 'a', 'b' and 'c' and the function :func:`func2` will be used for 311 | keys 'd' and 'e'. This could also be written as:: 312 | 313 | __conflict_solve = dict(func1='a b c',func2='d e') 314 | 315 | These functions will be called for each key they apply to with the 316 | form:: 317 | 318 | func1(self['a'], other['a']) 319 | 320 | The return value is used as the final merged value. 321 | 322 | As a convenience, merge() provides five (the most commonly needed) 323 | pre-defined policies: preserve, update, add, add_flip and add_s. The 324 | easiest explanation is their implementation:: 325 | 326 | preserve = lambda old,new: old 327 | update = lambda old,new: new 328 | add = lambda old,new: old + new 329 | add_flip = lambda old,new: new + old # note change of order! 330 | add_s = lambda old,new: old + ' ' + new # only for str! 331 | 332 | You can use those four words (as strings) as keys instead 333 | of defining them as functions, and the merge method will substitute 334 | the appropriate functions for you. 335 | 336 | For more complicated conflict resolution policies, you still need to 337 | construct your own functions. 338 | 339 | Examples 340 | -------- 341 | 342 | This show the default policy: 343 | 344 | >>> s = Struct(a=10,b=30) 345 | >>> s2 = Struct(a=20,c=40) 346 | >>> s.merge(s2) 347 | >>> sorted(s.items()) 348 | [('a', 10), ('b', 30), ('c', 40)] 349 | 350 | Now, show how to specify a conflict dict: 351 | 352 | >>> s = Struct(a=10,b=30) 353 | >>> s2 = Struct(a=20,b=40) 354 | >>> conflict = {'update':'a','add':'b'} 355 | >>> s.merge(s2,conflict) 356 | >>> sorted(s.items()) 357 | [('a', 20), ('b', 70)] 358 | """ 359 | 360 | data_dict = dict(__loc_data__,**kw) 361 | 362 | # policies for conflict resolution: two argument functions which return 363 | # the value that will go in the new struct 364 | preserve = lambda old,new: old 365 | update = lambda old,new: new 366 | add = lambda old,new: old + new 367 | add_flip = lambda old,new: new + old # note change of order! 368 | add_s = lambda old,new: old + ' ' + new 369 | 370 | # default policy is to keep current keys when there's a conflict 371 | conflict_solve = dict.fromkeys(self, preserve) 372 | 373 | # the conflict_solve dictionary is given by the user 'inverted': we 374 | # need a name-function mapping, it comes as a function -> names 375 | # dict. Make a local copy (b/c we'll make changes), replace user 376 | # strings for the three builtin policies and invert it. 377 | if __conflict_solve: 378 | inv_conflict_solve_user = __conflict_solve.copy() 379 | for name, func in [('preserve',preserve), ('update',update), 380 | ('add',add), ('add_flip',add_flip), 381 | ('add_s',add_s)]: 382 | if name in inv_conflict_solve_user.keys(): 383 | inv_conflict_solve_user[func] = inv_conflict_solve_user[name] 384 | del inv_conflict_solve_user[name] 385 | conflict_solve.update(self.__dict_invert(inv_conflict_solve_user)) 386 | for key in data_dict: 387 | if key not in self: 388 | self[key] = data_dict[key] 389 | else: 390 | self[key] = conflict_solve[key](self[key],data_dict[key]) 391 | 392 | -------------------------------------------------------------------------------- /external/nbformat/nbbase.py: -------------------------------------------------------------------------------- 1 | """The basic dict based notebook format. 2 | 3 | The Python representation of a notebook is a nested structure of 4 | dictionary subclasses that support attribute access 5 | (.ipstruct.Struct). The functions in this module are merely 6 | helpers to build the structs in the right form. 7 | 8 | Authors: 9 | 10 | * Brian Granger 11 | """ 12 | 13 | #----------------------------------------------------------------------------- 14 | # Copyright (C) 2008-2011 The IPython Development Team 15 | # 16 | # Distributed under the terms of the BSD License. The full license is in 17 | # the file COPYING, distributed as part of this software. 18 | #----------------------------------------------------------------------------- 19 | 20 | #----------------------------------------------------------------------------- 21 | # Imports 22 | #----------------------------------------------------------------------------- 23 | 24 | import pprint 25 | import uuid 26 | 27 | from .ipstruct import Struct 28 | 29 | #----------------------------------------------------------------------------- 30 | # Code 31 | #----------------------------------------------------------------------------- 32 | 33 | # Change this when incrementing the nbformat version 34 | nbformat = 3 35 | nbformat_minor = 0 36 | 37 | class NotebookNode(Struct): 38 | pass 39 | 40 | 41 | def from_dict(d): 42 | if isinstance(d, dict): 43 | newd = NotebookNode() 44 | for k,v in d.items(): 45 | newd[k] = from_dict(v) 46 | return newd 47 | elif isinstance(d, (tuple, list)): 48 | return [from_dict(i) for i in d] 49 | else: 50 | return d 51 | 52 | 53 | def new_output(output_type=None, output_text=None, output_png=None, 54 | output_html=None, output_svg=None, output_latex=None, output_json=None, 55 | output_javascript=None, output_jpeg=None, prompt_number=None, 56 | ename=None, evalue=None, traceback=None, stream=None, metadata=None): 57 | """Create a new code cell with input and output""" 58 | output = NotebookNode() 59 | if output_type is not None: 60 | output.output_type = unicode(output_type) 61 | 62 | if metadata is None: 63 | metadata = {} 64 | if not isinstance(metadata, dict): 65 | raise TypeError("metadata must be dict") 66 | output.metadata = metadata 67 | 68 | if output_type != 'pyerr': 69 | if output_text is not None: 70 | output.text = unicode(output_text) 71 | if output_png is not None: 72 | output.png = bytes(output_png) 73 | if output_jpeg is not None: 74 | output.jpeg = bytes(output_jpeg) 75 | if output_html is not None: 76 | output.html = unicode(output_html) 77 | if output_svg is not None: 78 | output.svg = unicode(output_svg) 79 | if output_latex is not None: 80 | output.latex = unicode(output_latex) 81 | if output_json is not None: 82 | output.json = unicode(output_json) 83 | if output_javascript is not None: 84 | output.javascript = unicode(output_javascript) 85 | 86 | if output_type == u'pyout': 87 | if prompt_number is not None: 88 | output.prompt_number = int(prompt_number) 89 | 90 | if output_type == u'pyerr': 91 | if ename is not None: 92 | output.ename = unicode(ename) 93 | if evalue is not None: 94 | output.evalue = unicode(evalue) 95 | if traceback is not None: 96 | output.traceback = [unicode(frame) for frame in list(traceback)] 97 | 98 | if output_type == u'stream': 99 | output.stream = 'stdout' if stream is None else unicode(stream) 100 | 101 | return output 102 | 103 | 104 | def new_code_cell(input=None, prompt_number=None, outputs=None, 105 | language=u'python', collapsed=False, metadata=None): 106 | """Create a new code cell with input and output""" 107 | cell = NotebookNode() 108 | cell.cell_type = u'code' 109 | if language is not None: 110 | cell.language = unicode(language) 111 | if input is not None: 112 | cell.input = unicode(input) 113 | if prompt_number is not None: 114 | cell.prompt_number = int(prompt_number) 115 | if outputs is None: 116 | cell.outputs = [] 117 | else: 118 | cell.outputs = outputs 119 | if collapsed is not None: 120 | cell.collapsed = bool(collapsed) 121 | cell.metadata = NotebookNode(metadata or {}) 122 | 123 | return cell 124 | 125 | def new_text_cell(cell_type, source=None, rendered=None, metadata=None): 126 | """Create a new text cell.""" 127 | cell = NotebookNode() 128 | # VERSIONHACK: plaintext -> raw 129 | # handle never-released plaintext name for raw cells 130 | if cell_type == 'plaintext': 131 | cell_type = 'raw' 132 | if source is not None: 133 | cell.source = unicode(source) 134 | if rendered is not None: 135 | cell.rendered = unicode(rendered) 136 | cell.metadata = NotebookNode(metadata or {}) 137 | cell.cell_type = cell_type 138 | return cell 139 | 140 | 141 | def new_heading_cell(source=None, rendered=None, level=1, metadata=None): 142 | """Create a new section cell with a given integer level.""" 143 | cell = NotebookNode() 144 | cell.cell_type = u'heading' 145 | if source is not None: 146 | cell.source = unicode(source) 147 | if rendered is not None: 148 | cell.rendered = unicode(rendered) 149 | cell.level = int(level) 150 | cell.metadata = NotebookNode(metadata or {}) 151 | return cell 152 | 153 | 154 | def new_worksheet(name=None, cells=None, metadata=None): 155 | """Create a worksheet by name with with a list of cells.""" 156 | ws = NotebookNode() 157 | if name is not None: 158 | ws.name = unicode(name) 159 | if cells is None: 160 | ws.cells = [] 161 | else: 162 | ws.cells = list(cells) 163 | ws.metadata = NotebookNode(metadata or {}) 164 | return ws 165 | 166 | 167 | def new_notebook(name=None, metadata=None, worksheets=None): 168 | """Create a notebook by name, id and a list of worksheets.""" 169 | nb = NotebookNode() 170 | nb.nbformat = nbformat 171 | nb.nbformat_minor = nbformat_minor 172 | if worksheets is None: 173 | nb.worksheets = [] 174 | else: 175 | nb.worksheets = list(worksheets) 176 | if metadata is None: 177 | nb.metadata = new_metadata() 178 | else: 179 | nb.metadata = NotebookNode(metadata) 180 | if name is not None: 181 | nb.metadata.name = unicode(name) 182 | return nb 183 | 184 | 185 | def new_metadata(name=None, authors=None, license=None, created=None, 186 | modified=None, gistid=None): 187 | """Create a new metadata node.""" 188 | metadata = NotebookNode() 189 | if name is not None: 190 | metadata.name = unicode(name) 191 | if authors is not None: 192 | metadata.authors = list(authors) 193 | if created is not None: 194 | metadata.created = unicode(created) 195 | if modified is not None: 196 | metadata.modified = unicode(modified) 197 | if license is not None: 198 | metadata.license = unicode(license) 199 | if gistid is not None: 200 | metadata.gistid = unicode(gistid) 201 | return metadata 202 | 203 | def new_author(name=None, email=None, affiliation=None, url=None): 204 | """Create a new author.""" 205 | author = NotebookNode() 206 | if name is not None: 207 | author.name = unicode(name) 208 | if email is not None: 209 | author.email = unicode(email) 210 | if affiliation is not None: 211 | author.affiliation = unicode(affiliation) 212 | if url is not None: 213 | author.url = unicode(url) 214 | return author 215 | 216 | -------------------------------------------------------------------------------- /external/nbformat/nbjson.py: -------------------------------------------------------------------------------- 1 | """Read and write notebooks in JSON format. 2 | 3 | Authors: 4 | 5 | * Brian Granger 6 | """ 7 | 8 | #----------------------------------------------------------------------------- 9 | # Copyright (C) 2008-2011 The IPython Development Team 10 | # 11 | # Distributed under the terms of the BSD License. The full license is in 12 | # the file COPYING, distributed as part of this software. 13 | #----------------------------------------------------------------------------- 14 | 15 | #----------------------------------------------------------------------------- 16 | # Imports 17 | #----------------------------------------------------------------------------- 18 | 19 | import copy 20 | import json 21 | 22 | from .nbbase import from_dict 23 | from .rwbase import ( 24 | NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines 25 | ) 26 | 27 | from . import py3compat 28 | 29 | #----------------------------------------------------------------------------- 30 | # Code 31 | #----------------------------------------------------------------------------- 32 | 33 | class BytesEncoder(json.JSONEncoder): 34 | """A JSON encoder that accepts b64 (and other *ascii*) bytestrings.""" 35 | def default(self, obj): 36 | if isinstance(obj, bytes): 37 | return obj.decode('ascii') 38 | return json.JSONEncoder.default(self, obj) 39 | 40 | 41 | class JSONReader(NotebookReader): 42 | 43 | def reads(self, s, **kwargs): 44 | nb = json.loads(s, **kwargs) 45 | nb = self.to_notebook(nb, **kwargs) 46 | return nb 47 | 48 | def to_notebook(self, d, **kwargs): 49 | return restore_bytes(rejoin_lines(from_dict(d))) 50 | 51 | 52 | class JSONWriter(NotebookWriter): 53 | 54 | def writes(self, nb, **kwargs): 55 | kwargs['cls'] = BytesEncoder 56 | kwargs['indent'] = 1 57 | kwargs['sort_keys'] = True 58 | kwargs['separators'] = (',',': ') 59 | if kwargs.pop('split_lines', True): 60 | nb = split_lines(copy.deepcopy(nb)) 61 | return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8') 62 | 63 | 64 | _reader = JSONReader() 65 | _writer = JSONWriter() 66 | 67 | reads = _reader.reads 68 | read = _reader.read 69 | to_notebook = _reader.to_notebook 70 | write = _writer.write 71 | writes = _writer.writes 72 | 73 | -------------------------------------------------------------------------------- /external/nbformat/nbpy.py: -------------------------------------------------------------------------------- 1 | """Read and write notebooks as regular .py files. 2 | 3 | Authors: 4 | 5 | * Brian Granger 6 | """ 7 | 8 | #----------------------------------------------------------------------------- 9 | # Copyright (C) 2008-2011 The IPython Development Team 10 | # 11 | # Distributed under the terms of the BSD License. The full license is in 12 | # the file COPYING, distributed as part of this software. 13 | #----------------------------------------------------------------------------- 14 | 15 | #----------------------------------------------------------------------------- 16 | # Imports 17 | #----------------------------------------------------------------------------- 18 | 19 | import re 20 | from .rwbase import NotebookReader, NotebookWriter 21 | from .nbbase import ( 22 | new_code_cell, new_text_cell, new_worksheet, 23 | new_notebook, new_heading_cell, nbformat, nbformat_minor, 24 | ) 25 | 26 | #----------------------------------------------------------------------------- 27 | # Code 28 | #----------------------------------------------------------------------------- 29 | 30 | _encoding_declaration_re = re.compile(r"^#.*coding[:=]\s*([-\w.]+)") 31 | 32 | class PyReaderError(Exception): 33 | pass 34 | 35 | 36 | class PyReader(NotebookReader): 37 | 38 | def reads(self, s, **kwargs): 39 | return self.to_notebook(s,**kwargs) 40 | 41 | def to_notebook(self, s, **kwargs): 42 | lines = s.splitlines() 43 | cells = [] 44 | cell_lines = [] 45 | kwargs = {} 46 | state = u'codecell' 47 | for line in lines: 48 | if line.startswith(u'# ') or _encoding_declaration_re.match(line): 49 | pass 50 | elif line.startswith(u'# '): 51 | cell = self.new_cell(state, cell_lines, **kwargs) 52 | if cell is not None: 53 | cells.append(cell) 54 | state = u'codecell' 55 | cell_lines = [] 56 | kwargs = {} 57 | elif line.startswith(u'# '): 58 | cell = self.new_cell(state, cell_lines, **kwargs) 59 | if cell is not None: 60 | cells.append(cell) 61 | state = u'htmlcell' 62 | cell_lines = [] 63 | kwargs = {} 64 | elif line.startswith(u'# '): 65 | cell = self.new_cell(state, cell_lines, **kwargs) 66 | if cell is not None: 67 | cells.append(cell) 68 | state = u'markdowncell' 69 | cell_lines = [] 70 | kwargs = {} 71 | # VERSIONHACK: plaintext -> raw 72 | elif line.startswith(u'# ') or line.startswith(u'# '): 73 | cell = self.new_cell(state, cell_lines, **kwargs) 74 | if cell is not None: 75 | cells.append(cell) 76 | state = u'rawcell' 77 | cell_lines = [] 78 | kwargs = {} 79 | elif line.startswith(u'# \d)>',line) 85 | if m is not None: 86 | state = u'headingcell' 87 | kwargs = {} 88 | kwargs['level'] = int(m.group('level')) 89 | else: 90 | state = u'codecell' 91 | kwargs = {} 92 | cell_lines = [] 93 | else: 94 | cell_lines.append(line) 95 | if cell_lines and state == u'codecell': 96 | cell = self.new_cell(state, cell_lines) 97 | if cell is not None: 98 | cells.append(cell) 99 | ws = new_worksheet(cells=cells) 100 | nb = new_notebook(worksheets=[ws]) 101 | return nb 102 | 103 | def new_cell(self, state, lines, **kwargs): 104 | if state == u'codecell': 105 | input = u'\n'.join(lines) 106 | input = input.strip(u'\n') 107 | if input: 108 | return new_code_cell(input=input) 109 | elif state == u'htmlcell': 110 | text = self._remove_comments(lines) 111 | if text: 112 | return new_text_cell(u'html',source=text) 113 | elif state == u'markdowncell': 114 | text = self._remove_comments(lines) 115 | if text: 116 | return new_text_cell(u'markdown',source=text) 117 | elif state == u'rawcell': 118 | text = self._remove_comments(lines) 119 | if text: 120 | return new_text_cell(u'raw',source=text) 121 | elif state == u'headingcell': 122 | text = self._remove_comments(lines) 123 | level = kwargs.get('level',1) 124 | if text: 125 | return new_heading_cell(source=text,level=level) 126 | 127 | def _remove_comments(self, lines): 128 | new_lines = [] 129 | for line in lines: 130 | if line.startswith(u'#'): 131 | new_lines.append(line[2:]) 132 | else: 133 | new_lines.append(line) 134 | text = u'\n'.join(new_lines) 135 | text = text.strip(u'\n') 136 | return text 137 | 138 | def split_lines_into_blocks(self, lines): 139 | if len(lines) == 1: 140 | yield lines[0] 141 | raise StopIteration() 142 | import ast 143 | source = '\n'.join(lines) 144 | code = ast.parse(source) 145 | starts = [x.lineno-1 for x in code.body] 146 | for i in range(len(starts)-1): 147 | yield '\n'.join(lines[starts[i]:starts[i+1]]).strip('\n') 148 | yield '\n'.join(lines[starts[-1]:]).strip('\n') 149 | 150 | 151 | class PyWriter(NotebookWriter): 152 | 153 | def writes(self, nb, **kwargs): 154 | lines = [u'# -*- coding: utf-8 -*-'] 155 | lines.extend([ 156 | u'# %i.%i' % (nbformat, nbformat_minor), 157 | u'', 158 | ]) 159 | for ws in nb.worksheets: 160 | for cell in ws.cells: 161 | if cell.cell_type == u'code': 162 | input = cell.get(u'input') 163 | if input is not None: 164 | lines.extend([u'# ',u'']) 165 | lines.extend(input.splitlines()) 166 | lines.append(u'') 167 | elif cell.cell_type == u'html': 168 | input = cell.get(u'source') 169 | if input is not None: 170 | lines.extend([u'# ',u'']) 171 | lines.extend([u'# ' + line for line in input.splitlines()]) 172 | lines.append(u'') 173 | elif cell.cell_type == u'markdown': 174 | input = cell.get(u'source') 175 | if input is not None: 176 | lines.extend([u'# ',u'']) 177 | lines.extend([u'# ' + line for line in input.splitlines()]) 178 | lines.append(u'') 179 | elif cell.cell_type == u'raw': 180 | input = cell.get(u'source') 181 | if input is not None: 182 | lines.extend([u'# ',u'']) 183 | lines.extend([u'# ' + line for line in input.splitlines()]) 184 | lines.append(u'') 185 | elif cell.cell_type == u'heading': 186 | input = cell.get(u'source') 187 | level = cell.get(u'level',1) 188 | if input is not None: 189 | lines.extend([u'# ' % level,u'']) 190 | lines.extend([u'# ' + line for line in input.splitlines()]) 191 | lines.append(u'') 192 | lines.append('') 193 | return unicode('\n'.join(lines)) 194 | 195 | 196 | _reader = PyReader() 197 | _writer = PyWriter() 198 | 199 | reads = _reader.reads 200 | read = _reader.read 201 | to_notebook = _reader.to_notebook 202 | write = _writer.write 203 | writes = _writer.writes 204 | 205 | -------------------------------------------------------------------------------- /external/nbformat/py3compat.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """Compatibility tricks for Python 3. Mainly to do with unicode.""" 3 | import __builtin__ 4 | import functools 5 | import sys 6 | import re 7 | import types 8 | 9 | from .encoding import DEFAULT_ENCODING 10 | 11 | orig_open = open 12 | 13 | def no_code(x, encoding=None): 14 | return x 15 | 16 | def decode(s, encoding=None): 17 | encoding = encoding or DEFAULT_ENCODING 18 | return s.decode(encoding, "replace") 19 | 20 | def encode(u, encoding=None): 21 | encoding = encoding or DEFAULT_ENCODING 22 | return u.encode(encoding, "replace") 23 | 24 | 25 | def cast_unicode(s, encoding=None): 26 | if isinstance(s, bytes): 27 | return decode(s, encoding) 28 | return s 29 | 30 | def cast_bytes(s, encoding=None): 31 | if not isinstance(s, bytes): 32 | return encode(s, encoding) 33 | return s 34 | 35 | def _modify_str_or_docstring(str_change_func): 36 | @functools.wraps(str_change_func) 37 | def wrapper(func_or_str): 38 | if isinstance(func_or_str, basestring): 39 | func = None 40 | doc = func_or_str 41 | else: 42 | func = func_or_str 43 | doc = func.__doc__ 44 | 45 | doc = str_change_func(doc) 46 | 47 | if func: 48 | func.__doc__ = doc 49 | return func 50 | return doc 51 | return wrapper 52 | 53 | if sys.version_info[0] >= 3: 54 | PY3 = True 55 | 56 | input = input 57 | builtin_mod_name = "builtins" 58 | 59 | str_to_unicode = no_code 60 | unicode_to_str = no_code 61 | str_to_bytes = encode 62 | bytes_to_str = decode 63 | cast_bytes_py2 = no_code 64 | 65 | string_types = (str,) 66 | 67 | def isidentifier(s, dotted=False): 68 | if dotted: 69 | return all(isidentifier(a) for a in s.split(".")) 70 | return s.isidentifier() 71 | 72 | open = orig_open 73 | 74 | MethodType = types.MethodType 75 | 76 | def execfile(fname, glob, loc=None): 77 | loc = loc if (loc is not None) else glob 78 | with open(fname, 'rb') as f: 79 | exec compile(f.read(), fname, 'exec') in glob, loc 80 | 81 | # Refactor print statements in doctests. 82 | _print_statement_re = re.compile(r"\bprint (?P.*)$", re.MULTILINE) 83 | def _print_statement_sub(match): 84 | expr = match.groups('expr') 85 | return "print(%s)" % expr 86 | 87 | @_modify_str_or_docstring 88 | def doctest_refactor_print(doc): 89 | """Refactor 'print x' statements in a doctest to print(x) style. 2to3 90 | unfortunately doesn't pick up on our doctests. 91 | 92 | Can accept a string or a function, so it can be used as a decorator.""" 93 | return _print_statement_re.sub(_print_statement_sub, doc) 94 | 95 | # Abstract u'abc' syntax: 96 | @_modify_str_or_docstring 97 | def u_format(s): 98 | """"{u}'abc'" --> "'abc'" (Python 3) 99 | 100 | Accepts a string or a function, so it can be used as a decorator.""" 101 | return s.format(u='') 102 | 103 | else: 104 | PY3 = False 105 | 106 | input = raw_input 107 | builtin_mod_name = "__builtin__" 108 | 109 | str_to_unicode = decode 110 | unicode_to_str = encode 111 | str_to_bytes = no_code 112 | bytes_to_str = no_code 113 | cast_bytes_py2 = cast_bytes 114 | 115 | string_types = (str, unicode) 116 | 117 | import re 118 | _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$") 119 | def isidentifier(s, dotted=False): 120 | if dotted: 121 | return all(isidentifier(a) for a in s.split(".")) 122 | return bool(_name_re.match(s)) 123 | 124 | class open(object): 125 | """Wrapper providing key part of Python 3 open() interface.""" 126 | def __init__(self, fname, mode="r", encoding="utf-8"): 127 | self.f = orig_open(fname, mode) 128 | self.enc = encoding 129 | 130 | def write(self, s): 131 | return self.f.write(s.encode(self.enc)) 132 | 133 | def read(self, size=-1): 134 | return self.f.read(size).decode(self.enc) 135 | 136 | def close(self): 137 | return self.f.close() 138 | 139 | def __enter__(self): 140 | return self 141 | 142 | def __exit__(self, etype, value, traceback): 143 | self.f.close() 144 | 145 | def MethodType(func, instance): 146 | return types.MethodType(func, instance, type(instance)) 147 | 148 | # don't override system execfile on 2.x: 149 | execfile = execfile 150 | 151 | def doctest_refactor_print(func_or_str): 152 | return func_or_str 153 | 154 | 155 | # Abstract u'abc' syntax: 156 | @_modify_str_or_docstring 157 | def u_format(s): 158 | """"{u}'abc'" --> "u'abc'" (Python 2) 159 | 160 | Accepts a string or a function, so it can be used as a decorator.""" 161 | return s.format(u='u') 162 | 163 | if sys.platform == 'win32': 164 | def execfile(fname, glob=None, loc=None): 165 | loc = loc if (loc is not None) else glob 166 | # The rstrip() is necessary b/c trailing whitespace in files will 167 | # cause an IndentationError in Python 2.6 (this was fixed in 2.7, 168 | # but we still support 2.6). See issue 1027. 169 | scripttext = __builtin__.open(fname).read().rstrip() + '\n' 170 | # compile converts unicode filename to str assuming 171 | # ascii. Let's do the conversion before calling compile 172 | if isinstance(fname, unicode): 173 | filename = unicode_to_str(fname) 174 | else: 175 | filename = fname 176 | exec compile(scripttext, filename, 'exec') in glob, loc 177 | else: 178 | def execfile(fname, *where): 179 | if isinstance(fname, unicode): 180 | filename = fname.encode(sys.getfilesystemencoding()) 181 | else: 182 | filename = fname 183 | __builtin__.execfile(filename, *where) 184 | -------------------------------------------------------------------------------- /external/nbformat/rwbase.py: -------------------------------------------------------------------------------- 1 | """Base classes and utilities for readers and writers. 2 | 3 | Authors: 4 | 5 | * Brian Granger 6 | """ 7 | 8 | #----------------------------------------------------------------------------- 9 | # Copyright (C) 2008-2011 The IPython Development Team 10 | # 11 | # Distributed under the terms of the BSD License. The full license is in 12 | # the file COPYING, distributed as part of this software. 13 | #----------------------------------------------------------------------------- 14 | 15 | #----------------------------------------------------------------------------- 16 | # Imports 17 | #----------------------------------------------------------------------------- 18 | 19 | from base64 import encodestring, decodestring 20 | import pprint 21 | 22 | from . import py3compat 23 | 24 | str_to_bytes = py3compat.str_to_bytes 25 | 26 | #----------------------------------------------------------------------------- 27 | # Code 28 | #----------------------------------------------------------------------------- 29 | 30 | def restore_bytes(nb): 31 | """Restore bytes of image data from unicode-only formats. 32 | 33 | Base64 encoding is handled elsewhere. Bytes objects in the notebook are 34 | always b64-encoded. We DO NOT encode/decode around file formats. 35 | """ 36 | for ws in nb.worksheets: 37 | for cell in ws.cells: 38 | if cell.cell_type == 'code': 39 | for output in cell.outputs: 40 | if 'png' in output: 41 | output.png = str_to_bytes(output.png, 'ascii') 42 | if 'jpeg' in output: 43 | output.jpeg = str_to_bytes(output.jpeg, 'ascii') 44 | return nb 45 | 46 | # output keys that are likely to have multiline values 47 | _multiline_outputs = ['text', 'html', 'svg', 'latex', 'javascript', 'json'] 48 | 49 | 50 | # FIXME: workaround for old splitlines() 51 | def _join_lines(lines): 52 | """join lines that have been written by splitlines() 53 | 54 | Has logic to protect against `splitlines()`, which 55 | should have been `splitlines(True)` 56 | """ 57 | if lines and lines[0].endswith(('\n', '\r')): 58 | # created by splitlines(True) 59 | return u''.join(lines) 60 | else: 61 | # created by splitlines() 62 | return u'\n'.join(lines) 63 | 64 | 65 | def rejoin_lines(nb): 66 | """rejoin multiline text into strings 67 | 68 | For reversing effects of ``split_lines(nb)``. 69 | 70 | This only rejoins lines that have been split, so if text objects were not split 71 | they will pass through unchanged. 72 | 73 | Used when reading JSON files that may have been passed through split_lines. 74 | """ 75 | for ws in nb.worksheets: 76 | for cell in ws.cells: 77 | if cell.cell_type == 'code': 78 | if 'input' in cell and isinstance(cell.input, list): 79 | cell.input = _join_lines(cell.input) 80 | for output in cell.outputs: 81 | for key in _multiline_outputs: 82 | item = output.get(key, None) 83 | if isinstance(item, list): 84 | output[key] = _join_lines(item) 85 | else: # text, heading cell 86 | for key in ['source', 'rendered']: 87 | item = cell.get(key, None) 88 | if isinstance(item, list): 89 | cell[key] = _join_lines(item) 90 | return nb 91 | 92 | 93 | def split_lines(nb): 94 | """split likely multiline text into lists of strings 95 | 96 | For file output more friendly to line-based VCS. ``rejoin_lines(nb)`` will 97 | reverse the effects of ``split_lines(nb)``. 98 | 99 | Used when writing JSON files. 100 | """ 101 | for ws in nb.worksheets: 102 | for cell in ws.cells: 103 | if cell.cell_type == 'code': 104 | if 'input' in cell and isinstance(cell.input, basestring): 105 | cell.input = cell.input.splitlines(True) 106 | for output in cell.outputs: 107 | for key in _multiline_outputs: 108 | item = output.get(key, None) 109 | if isinstance(item, basestring): 110 | output[key] = item.splitlines(True) 111 | else: # text, heading cell 112 | for key in ['source', 'rendered']: 113 | item = cell.get(key, None) 114 | if isinstance(item, basestring): 115 | cell[key] = item.splitlines(True) 116 | return nb 117 | 118 | # b64 encode/decode are never actually used, because all bytes objects in 119 | # the notebook are already b64-encoded, and we don't need/want to double-encode 120 | 121 | def base64_decode(nb): 122 | """Restore all bytes objects in the notebook from base64-encoded strings. 123 | 124 | Note: This is never used 125 | """ 126 | for ws in nb.worksheets: 127 | for cell in ws.cells: 128 | if cell.cell_type == 'code': 129 | for output in cell.outputs: 130 | if 'png' in output: 131 | if isinstance(output.png, unicode): 132 | output.png = output.png.encode('ascii') 133 | output.png = decodestring(output.png) 134 | if 'jpeg' in output: 135 | if isinstance(output.jpeg, unicode): 136 | output.jpeg = output.jpeg.encode('ascii') 137 | output.jpeg = decodestring(output.jpeg) 138 | return nb 139 | 140 | 141 | def base64_encode(nb): 142 | """Base64 encode all bytes objects in the notebook. 143 | 144 | These will be b64-encoded unicode strings 145 | 146 | Note: This is never used 147 | """ 148 | for ws in nb.worksheets: 149 | for cell in ws.cells: 150 | if cell.cell_type == 'code': 151 | for output in cell.outputs: 152 | if 'png' in output: 153 | output.png = encodestring(output.png).decode('ascii') 154 | if 'jpeg' in output: 155 | output.jpeg = encodestring(output.jpeg).decode('ascii') 156 | return nb 157 | 158 | 159 | class NotebookReader(object): 160 | """A class for reading notebooks.""" 161 | 162 | def reads(self, s, **kwargs): 163 | """Read a notebook from a string.""" 164 | raise NotImplementedError("loads must be implemented in a subclass") 165 | 166 | def read(self, fp, **kwargs): 167 | """Read a notebook from a file like object""" 168 | nbs = fp.read() 169 | if not py3compat.PY3 and not isinstance(nbs, unicode): 170 | nbs = py3compat.str_to_unicode(nbs) 171 | return self.reads(nbs, **kwargs) 172 | 173 | 174 | class NotebookWriter(object): 175 | """A class for writing notebooks.""" 176 | 177 | def writes(self, nb, **kwargs): 178 | """Write a notebook to a string.""" 179 | raise NotImplementedError("loads must be implemented in a subclass") 180 | 181 | def write(self, nb, fp, **kwargs): 182 | """Write a notebook to a file like object""" 183 | nbs = self.writes(nb,**kwargs) 184 | if not py3compat.PY3 and not isinstance(nbs, unicode): 185 | # this branch is likely only taken for JSON on Python 2 186 | nbs = py3compat.str_to_unicode(nbs) 187 | return fp.write(nbs) 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /external/nbformat3/COPYING.txt: -------------------------------------------------------------------------------- 1 | ============================= 2 | The IPython licensing terms 3 | ============================= 4 | 5 | IPython is licensed under the terms of the Modified BSD License (also known as 6 | New or Revised BSD), as follows: 7 | 8 | Copyright (c) 2008-2010, IPython Development Team 9 | Copyright (c) 2001-2007, Fernando Perez. 10 | Copyright (c) 2001, Janko Hauser 11 | Copyright (c) 2001, Nathaniel Gray 12 | 13 | All rights reserved. 14 | 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions are met: 17 | 18 | Redistributions of source code must retain the above copyright notice, this 19 | list of conditions and the following disclaimer. 20 | 21 | Redistributions in binary form must reproduce the above copyright notice, this 22 | list of conditions and the following disclaimer in the documentation and/or 23 | other materials provided with the distribution. 24 | 25 | Neither the name of the IPython Development Team nor the names of its 26 | contributors may be used to endorse or promote products derived from this 27 | software without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 30 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 31 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 33 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 36 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 37 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | 40 | About the IPython Development Team 41 | ---------------------------------- 42 | 43 | Fernando Perez began IPython in 2001 based on code from Janko Hauser 44 | and Nathaniel Gray . Fernando is still 45 | the project lead. 46 | 47 | The IPython Development Team is the set of all contributors to the IPython 48 | project. This includes all of the IPython subprojects. A full list with 49 | details is kept in the documentation directory, in the file 50 | ``about/credits.txt``. 51 | 52 | The core team that coordinates development on GitHub can be found here: 53 | http://github.com/ipython. As of late 2010, it consists of: 54 | 55 | * Brian E. Granger 56 | * Jonathan March 57 | * Evan Patterson 58 | * Fernando Perez 59 | * Min Ragan-Kelley 60 | * Robert Kern 61 | 62 | 63 | Our Copyright Policy 64 | -------------------- 65 | 66 | IPython uses a shared copyright model. Each contributor maintains copyright 67 | over their contributions to IPython. But, it is important to note that these 68 | contributions are typically only changes to the repositories. Thus, the IPython 69 | source code, in its entirety is not the copyright of any single person or 70 | institution. Instead, it is the collective copyright of the entire IPython 71 | Development Team. If individual contributors want to maintain a record of what 72 | changes/contributions they have specific copyright on, they should indicate 73 | their copyright in the commit message of the change, when they commit the 74 | change to one of the IPython repositories. 75 | 76 | With this in mind, the following banner should be used in any source code file 77 | to indicate the copyright and license terms: 78 | 79 | #----------------------------------------------------------------------------- 80 | # Copyright (c) 2010, IPython Development Team. 81 | # 82 | # Distributed under the terms of the Modified BSD License. 83 | # 84 | # The full license is in the file COPYING.txt, distributed with this software. 85 | #----------------------------------------------------------------------------- 86 | -------------------------------------------------------------------------------- /external/nbformat3/__init__.py: -------------------------------------------------------------------------------- 1 | """The main API for the v3 notebook format. 2 | 3 | Authors: 4 | 5 | * Brian Granger 6 | """ 7 | 8 | #----------------------------------------------------------------------------- 9 | # Copyright (C) 2008-2011 The IPython Development Team 10 | # 11 | # Distributed under the terms of the BSD License. The full license is in 12 | # the file COPYING, distributed as part of this software. 13 | #----------------------------------------------------------------------------- 14 | 15 | #----------------------------------------------------------------------------- 16 | # Imports 17 | #----------------------------------------------------------------------------- 18 | 19 | from .nbbase import ( 20 | NotebookNode, 21 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, 22 | new_metadata, new_author, new_heading_cell, nbformat, nbformat_minor 23 | ) 24 | 25 | from .nbjson import reads as reads_json, writes as writes_json 26 | from .nbjson import reads as read_json, writes as write_json 27 | from .nbjson import to_notebook as to_notebook_json 28 | 29 | from .nbpy import reads as reads_py, writes as writes_py 30 | from .nbpy import reads as read_py, writes as write_py 31 | from .nbpy import to_notebook as to_notebook_py 32 | 33 | 34 | #----------------------------------------------------------------------------- 35 | # Code 36 | #----------------------------------------------------------------------------- 37 | 38 | def parse_filename(fname): 39 | """Parse a notebook filename. 40 | 41 | This function takes a notebook filename and returns the notebook 42 | format (json/py) and the notebook name. This logic can be 43 | summarized as follows: 44 | 45 | * notebook.ipynb -> (notebook.ipynb, notebook, json) 46 | * notebook.json -> (notebook.json, notebook, json) 47 | * notebook.py -> (notebook.py, notebook, py) 48 | * notebook -> (notebook.ipynb, notebook, json) 49 | 50 | Parameters 51 | ---------- 52 | fname : unicode 53 | The notebook filename. The filename can use a specific filename 54 | extention (.ipynb, .json, .py) or none, in which case .ipynb will 55 | be assumed. 56 | 57 | Returns 58 | ------- 59 | (fname, name, format) : (unicode, unicode, unicode) 60 | The filename, notebook name and format. 61 | """ 62 | if fname.endswith('.ipynb'): 63 | format = 'json' 64 | elif fname.endswith('.json'): 65 | format = 'json' 66 | elif fname.endswith('.py'): 67 | format = 'py' 68 | else: 69 | fname = fname + '.ipynb' 70 | format = 'json' 71 | name = fname.split('.')[0] 72 | return fname, name, format 73 | 74 | -------------------------------------------------------------------------------- /external/nbformat3/data.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """Utilities for working with data structures like lists, dicts and tuples. 3 | """ 4 | 5 | #----------------------------------------------------------------------------- 6 | # Copyright (C) 2008-2011 The IPython Development Team 7 | # 8 | # Distributed under the terms of the BSD License. The full license is in 9 | # the file COPYING, distributed as part of this software. 10 | #----------------------------------------------------------------------------- 11 | 12 | def uniq_stable(elems): 13 | """uniq_stable(elems) -> list 14 | 15 | Return from an iterable, a list of all the unique elements in the input, 16 | but maintaining the order in which they first appear. 17 | 18 | Note: All elements in the input must be hashable for this routine 19 | to work, as it internally uses a set for efficiency reasons. 20 | """ 21 | seen = set() 22 | return [x for x in elems if x not in seen and not seen.add(x)] 23 | 24 | 25 | def flatten(seq): 26 | """Flatten a list of lists (NOT recursive, only works for 2d lists).""" 27 | 28 | return [x for subseq in seq for x in subseq] 29 | 30 | 31 | def chop(seq, size): 32 | """Chop a sequence into chunks of the given size.""" 33 | return [seq[i:i+size] for i in range(0,len(seq),size)] 34 | 35 | 36 | -------------------------------------------------------------------------------- /external/nbformat3/encoding.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Utilities for dealing with text encodings 4 | """ 5 | 6 | #----------------------------------------------------------------------------- 7 | # Copyright (C) 2008-2012 The IPython Development Team 8 | # 9 | # Distributed under the terms of the BSD License. The full license is in 10 | # the file COPYING, distributed as part of this software. 11 | #----------------------------------------------------------------------------- 12 | 13 | #----------------------------------------------------------------------------- 14 | # Imports 15 | #----------------------------------------------------------------------------- 16 | import sys 17 | import locale 18 | 19 | # to deal with the possibility of sys.std* not being a stream at all 20 | def get_stream_enc(stream, default=None): 21 | """Return the given stream's encoding or a default. 22 | 23 | There are cases where ``sys.std*`` might not actually be a stream, so 24 | check for the encoding attribute prior to returning it, and return 25 | a default if it doesn't exist or evaluates as False. ``default`` 26 | is None if not provided. 27 | """ 28 | if not hasattr(stream, 'encoding') or not stream.encoding: 29 | return default 30 | else: 31 | return stream.encoding 32 | 33 | # Less conservative replacement for sys.getdefaultencoding, that will try 34 | # to match the environment. 35 | # Defined here as central function, so if we find better choices, we 36 | # won't need to make changes all over IPython. 37 | def getdefaultencoding(): 38 | """Return IPython's guess for the default encoding for bytes as text. 39 | 40 | Asks for stdin.encoding first, to match the calling Terminal, but that 41 | is often None for subprocesses. Fall back on locale.getpreferredencoding() 42 | which should be a sensible platform default (that respects LANG environment), 43 | and finally to sys.getdefaultencoding() which is the most conservative option, 44 | and usually ASCII. 45 | """ 46 | enc = get_stream_enc(sys.stdin) 47 | if not enc or enc=='ascii': 48 | try: 49 | # There are reports of getpreferredencoding raising errors 50 | # in some cases, which may well be fixed, but let's be conservative here. 51 | enc = locale.getpreferredencoding() 52 | except Exception: 53 | pass 54 | return enc or sys.getdefaultencoding() 55 | 56 | DEFAULT_ENCODING = getdefaultencoding() 57 | -------------------------------------------------------------------------------- /external/nbformat3/ipstruct.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | """A dict subclass that supports attribute style access. 3 | 4 | Authors: 5 | 6 | * Fernando Perez (original) 7 | * Brian Granger (refactoring to a dict subclass) 8 | """ 9 | 10 | #----------------------------------------------------------------------------- 11 | # Copyright (C) 2008-2011 The IPython Development Team 12 | # 13 | # Distributed under the terms of the BSD License. The full license is in 14 | # the file COPYING, distributed as part of this software. 15 | #----------------------------------------------------------------------------- 16 | 17 | #----------------------------------------------------------------------------- 18 | # Imports 19 | #----------------------------------------------------------------------------- 20 | 21 | __all__ = ['Struct'] 22 | 23 | #----------------------------------------------------------------------------- 24 | # Code 25 | #----------------------------------------------------------------------------- 26 | 27 | 28 | class Struct(dict): 29 | """A dict subclass with attribute style access. 30 | 31 | This dict subclass has a a few extra features: 32 | 33 | * Attribute style access. 34 | * Protection of class members (like keys, items) when using attribute 35 | style access. 36 | * The ability to restrict assignment to only existing keys. 37 | * Intelligent merging. 38 | * Overloaded operators. 39 | """ 40 | _allownew = True 41 | def __init__(self, *args, **kw): 42 | """Initialize with a dictionary, another Struct, or data. 43 | 44 | Parameters 45 | ---------- 46 | args : dict, Struct 47 | Initialize with one dict or Struct 48 | kw : dict 49 | Initialize with key, value pairs. 50 | 51 | Examples 52 | -------- 53 | 54 | >>> s = Struct(a=10,b=30) 55 | >>> s.a 56 | 10 57 | >>> s.b 58 | 30 59 | >>> s2 = Struct(s,c=30) 60 | >>> sorted(s2.keys()) 61 | ['a', 'b', 'c'] 62 | """ 63 | object.__setattr__(self, '_allownew', True) 64 | dict.__init__(self, *args, **kw) 65 | 66 | def __setitem__(self, key, value): 67 | """Set an item with check for allownew. 68 | 69 | Examples 70 | -------- 71 | 72 | >>> s = Struct() 73 | >>> s['a'] = 10 74 | >>> s.allow_new_attr(False) 75 | >>> s['a'] = 10 76 | >>> s['a'] 77 | 10 78 | >>> try: 79 | ... s['b'] = 20 80 | ... except KeyError: 81 | ... print 'this is not allowed' 82 | ... 83 | this is not allowed 84 | """ 85 | if not self._allownew and key not in self: 86 | raise KeyError( 87 | "can't create new attribute %s when allow_new_attr(False)" % key) 88 | dict.__setitem__(self, key, value) 89 | 90 | def __setattr__(self, key, value): 91 | """Set an attr with protection of class members. 92 | 93 | This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to 94 | :exc:`AttributeError`. 95 | 96 | Examples 97 | -------- 98 | 99 | >>> s = Struct() 100 | >>> s.a = 10 101 | >>> s.a 102 | 10 103 | >>> try: 104 | ... s.get = 10 105 | ... except AttributeError: 106 | ... print "you can't set a class member" 107 | ... 108 | you can't set a class member 109 | """ 110 | # If key is an str it might be a class member or instance var 111 | if isinstance(key, str): 112 | # I can't simply call hasattr here because it calls getattr, which 113 | # calls self.__getattr__, which returns True for keys in 114 | # self._data. But I only want keys in the class and in 115 | # self.__dict__ 116 | if key in self.__dict__ or hasattr(Struct, key): 117 | raise AttributeError( 118 | 'attr %s is a protected member of class Struct.' % key 119 | ) 120 | try: 121 | self.__setitem__(key, value) 122 | except KeyError as e: 123 | raise AttributeError(e) 124 | 125 | def __getattr__(self, key): 126 | """Get an attr by calling :meth:`dict.__getitem__`. 127 | 128 | Like :meth:`__setattr__`, this method converts :exc:`KeyError` to 129 | :exc:`AttributeError`. 130 | 131 | Examples 132 | -------- 133 | 134 | >>> s = Struct(a=10) 135 | >>> s.a 136 | 10 137 | >>> type(s.get) 138 | <... 'builtin_function_or_method'> 139 | >>> try: 140 | ... s.b 141 | ... except AttributeError: 142 | ... print "I don't have that key" 143 | ... 144 | I don't have that key 145 | """ 146 | try: 147 | result = self[key] 148 | except KeyError: 149 | raise AttributeError(key) 150 | else: 151 | return result 152 | 153 | def __iadd__(self, other): 154 | """s += s2 is a shorthand for s.merge(s2). 155 | 156 | Examples 157 | -------- 158 | 159 | >>> s = Struct(a=10,b=30) 160 | >>> s2 = Struct(a=20,c=40) 161 | >>> s += s2 162 | >>> sorted(s.keys()) 163 | ['a', 'b', 'c'] 164 | """ 165 | self.merge(other) 166 | return self 167 | 168 | def __add__(self,other): 169 | """s + s2 -> New Struct made from s.merge(s2). 170 | 171 | Examples 172 | -------- 173 | 174 | >>> s1 = Struct(a=10,b=30) 175 | >>> s2 = Struct(a=20,c=40) 176 | >>> s = s1 + s2 177 | >>> sorted(s.keys()) 178 | ['a', 'b', 'c'] 179 | """ 180 | sout = self.copy() 181 | sout.merge(other) 182 | return sout 183 | 184 | def __sub__(self,other): 185 | """s1 - s2 -> remove keys in s2 from s1. 186 | 187 | Examples 188 | -------- 189 | 190 | >>> s1 = Struct(a=10,b=30) 191 | >>> s2 = Struct(a=40) 192 | >>> s = s1 - s2 193 | >>> s 194 | {'b': 30} 195 | """ 196 | sout = self.copy() 197 | sout -= other 198 | return sout 199 | 200 | def __isub__(self,other): 201 | """Inplace remove keys from self that are in other. 202 | 203 | Examples 204 | -------- 205 | 206 | >>> s1 = Struct(a=10,b=30) 207 | >>> s2 = Struct(a=40) 208 | >>> s1 -= s2 209 | >>> s1 210 | {'b': 30} 211 | """ 212 | for k in list(other.keys()): 213 | if k in self: 214 | del self[k] 215 | return self 216 | 217 | def __dict_invert(self, data): 218 | """Helper function for merge. 219 | 220 | Takes a dictionary whose values are lists and returns a dict with 221 | the elements of each list as keys and the original keys as values. 222 | """ 223 | outdict = {} 224 | for k,lst in list(data.items()): 225 | if isinstance(lst, str): 226 | lst = lst.split() 227 | for entry in lst: 228 | outdict[entry] = k 229 | return outdict 230 | 231 | def dict(self): 232 | return self 233 | 234 | def copy(self): 235 | """Return a copy as a Struct. 236 | 237 | Examples 238 | -------- 239 | 240 | >>> s = Struct(a=10,b=30) 241 | >>> s2 = s.copy() 242 | >>> type(s2) is Struct 243 | True 244 | """ 245 | return Struct(dict.copy(self)) 246 | 247 | def hasattr(self, key): 248 | """hasattr function available as a method. 249 | 250 | Implemented like has_key. 251 | 252 | Examples 253 | -------- 254 | 255 | >>> s = Struct(a=10) 256 | >>> s.hasattr('a') 257 | True 258 | >>> s.hasattr('b') 259 | False 260 | >>> s.hasattr('get') 261 | False 262 | """ 263 | return key in self 264 | 265 | def allow_new_attr(self, allow = True): 266 | """Set whether new attributes can be created in this Struct. 267 | 268 | This can be used to catch typos by verifying that the attribute user 269 | tries to change already exists in this Struct. 270 | """ 271 | object.__setattr__(self, '_allownew', allow) 272 | 273 | def merge(self, __loc_data__=None, __conflict_solve=None, **kw): 274 | """Merge two Structs with customizable conflict resolution. 275 | 276 | This is similar to :meth:`update`, but much more flexible. First, a 277 | dict is made from data+key=value pairs. When merging this dict with 278 | the Struct S, the optional dictionary 'conflict' is used to decide 279 | what to do. 280 | 281 | If conflict is not given, the default behavior is to preserve any keys 282 | with their current value (the opposite of the :meth:`update` method's 283 | behavior). 284 | 285 | Parameters 286 | ---------- 287 | __loc_data : dict, Struct 288 | The data to merge into self 289 | __conflict_solve : dict 290 | The conflict policy dict. The keys are binary functions used to 291 | resolve the conflict and the values are lists of strings naming 292 | the keys the conflict resolution function applies to. Instead of 293 | a list of strings a space separated string can be used, like 294 | 'a b c'. 295 | kw : dict 296 | Additional key, value pairs to merge in 297 | 298 | Notes 299 | ----- 300 | 301 | The `__conflict_solve` dict is a dictionary of binary functions which will be used to 302 | solve key conflicts. Here is an example:: 303 | 304 | __conflict_solve = dict( 305 | func1=['a','b','c'], 306 | func2=['d','e'] 307 | ) 308 | 309 | In this case, the function :func:`func1` will be used to resolve 310 | keys 'a', 'b' and 'c' and the function :func:`func2` will be used for 311 | keys 'd' and 'e'. This could also be written as:: 312 | 313 | __conflict_solve = dict(func1='a b c',func2='d e') 314 | 315 | These functions will be called for each key they apply to with the 316 | form:: 317 | 318 | func1(self['a'], other['a']) 319 | 320 | The return value is used as the final merged value. 321 | 322 | As a convenience, merge() provides five (the most commonly needed) 323 | pre-defined policies: preserve, update, add, add_flip and add_s. The 324 | easiest explanation is their implementation:: 325 | 326 | preserve = lambda old,new: old 327 | update = lambda old,new: new 328 | add = lambda old,new: old + new 329 | add_flip = lambda old,new: new + old # note change of order! 330 | add_s = lambda old,new: old + ' ' + new # only for str! 331 | 332 | You can use those four words (as strings) as keys instead 333 | of defining them as functions, and the merge method will substitute 334 | the appropriate functions for you. 335 | 336 | For more complicated conflict resolution policies, you still need to 337 | construct your own functions. 338 | 339 | Examples 340 | -------- 341 | 342 | This show the default policy: 343 | 344 | >>> s = Struct(a=10,b=30) 345 | >>> s2 = Struct(a=20,c=40) 346 | >>> s.merge(s2) 347 | >>> sorted(s.items()) 348 | [('a', 10), ('b', 30), ('c', 40)] 349 | 350 | Now, show how to specify a conflict dict: 351 | 352 | >>> s = Struct(a=10,b=30) 353 | >>> s2 = Struct(a=20,b=40) 354 | >>> conflict = {'update':'a','add':'b'} 355 | >>> s.merge(s2,conflict) 356 | >>> sorted(s.items()) 357 | [('a', 20), ('b', 70)] 358 | """ 359 | 360 | data_dict = dict(__loc_data__,**kw) 361 | 362 | # policies for conflict resolution: two argument functions which return 363 | # the value that will go in the new struct 364 | preserve = lambda old,new: old 365 | update = lambda old,new: new 366 | add = lambda old,new: old + new 367 | add_flip = lambda old,new: new + old # note change of order! 368 | add_s = lambda old,new: old + ' ' + new 369 | 370 | # default policy is to keep current keys when there's a conflict 371 | conflict_solve = dict.fromkeys(self, preserve) 372 | 373 | # the conflict_solve dictionary is given by the user 'inverted': we 374 | # need a name-function mapping, it comes as a function -> names 375 | # dict. Make a local copy (b/c we'll make changes), replace user 376 | # strings for the three builtin policies and invert it. 377 | if __conflict_solve: 378 | inv_conflict_solve_user = __conflict_solve.copy() 379 | for name, func in [('preserve',preserve), ('update',update), 380 | ('add',add), ('add_flip',add_flip), 381 | ('add_s',add_s)]: 382 | if name in list(inv_conflict_solve_user.keys()): 383 | inv_conflict_solve_user[func] = inv_conflict_solve_user[name] 384 | del inv_conflict_solve_user[name] 385 | conflict_solve.update(self.__dict_invert(inv_conflict_solve_user)) 386 | for key in data_dict: 387 | if key not in self: 388 | self[key] = data_dict[key] 389 | else: 390 | self[key] = conflict_solve[key](self[key],data_dict[key]) 391 | 392 | -------------------------------------------------------------------------------- /external/nbformat3/nbbase.py: -------------------------------------------------------------------------------- 1 | """The basic dict based notebook format. 2 | 3 | The Python representation of a notebook is a nested structure of 4 | dictionary subclasses that support attribute access 5 | (.ipstruct.Struct). The functions in this module are merely 6 | helpers to build the structs in the right form. 7 | 8 | Authors: 9 | 10 | * Brian Granger 11 | """ 12 | 13 | #----------------------------------------------------------------------------- 14 | # Copyright (C) 2008-2011 The IPython Development Team 15 | # 16 | # Distributed under the terms of the BSD License. The full license is in 17 | # the file COPYING, distributed as part of this software. 18 | #----------------------------------------------------------------------------- 19 | 20 | #----------------------------------------------------------------------------- 21 | # Imports 22 | #----------------------------------------------------------------------------- 23 | 24 | import pprint 25 | import uuid 26 | 27 | from .ipstruct import Struct 28 | 29 | #----------------------------------------------------------------------------- 30 | # Code 31 | #----------------------------------------------------------------------------- 32 | 33 | # Change this when incrementing the nbformat version 34 | nbformat = 3 35 | nbformat_minor = 0 36 | 37 | class NotebookNode(Struct): 38 | pass 39 | 40 | 41 | def from_dict(d): 42 | if isinstance(d, dict): 43 | newd = NotebookNode() 44 | for k,v in list(d.items()): 45 | newd[k] = from_dict(v) 46 | return newd 47 | elif isinstance(d, (tuple, list)): 48 | return [from_dict(i) for i in d] 49 | else: 50 | return d 51 | 52 | 53 | def new_output(output_type=None, output_text=None, output_png=None, 54 | output_html=None, output_svg=None, output_latex=None, output_json=None, 55 | output_javascript=None, output_jpeg=None, prompt_number=None, 56 | ename=None, evalue=None, traceback=None, stream=None, metadata=None): 57 | """Create a new code cell with input and output""" 58 | output = NotebookNode() 59 | if output_type is not None: 60 | output.output_type = str(output_type) 61 | 62 | if metadata is None: 63 | metadata = {} 64 | if not isinstance(metadata, dict): 65 | raise TypeError("metadata must be dict") 66 | output.metadata = metadata 67 | 68 | if output_type != 'pyerr': 69 | if output_text is not None: 70 | output.text = str(output_text) 71 | if output_png is not None: 72 | output.png = bytes(output_png) 73 | if output_jpeg is not None: 74 | output.jpeg = bytes(output_jpeg) 75 | if output_html is not None: 76 | output.html = str(output_html) 77 | if output_svg is not None: 78 | output.svg = str(output_svg) 79 | if output_latex is not None: 80 | output.latex = str(output_latex) 81 | if output_json is not None: 82 | output.json = str(output_json) 83 | if output_javascript is not None: 84 | output.javascript = str(output_javascript) 85 | 86 | if output_type == 'pyout': 87 | if prompt_number is not None: 88 | output.prompt_number = int(prompt_number) 89 | 90 | if output_type == 'pyerr': 91 | if ename is not None: 92 | output.ename = str(ename) 93 | if evalue is not None: 94 | output.evalue = str(evalue) 95 | if traceback is not None: 96 | output.traceback = [str(frame) for frame in list(traceback)] 97 | 98 | if output_type == 'stream': 99 | output.stream = 'stdout' if stream is None else str(stream) 100 | 101 | return output 102 | 103 | 104 | def new_code_cell(input=None, prompt_number=None, outputs=None, 105 | language='python', collapsed=False, metadata=None): 106 | """Create a new code cell with input and output""" 107 | cell = NotebookNode() 108 | cell.cell_type = 'code' 109 | if language is not None: 110 | cell.language = str(language) 111 | if input is not None: 112 | cell.input = str(input) 113 | if prompt_number is not None: 114 | cell.prompt_number = int(prompt_number) 115 | if outputs is None: 116 | cell.outputs = [] 117 | else: 118 | cell.outputs = outputs 119 | if collapsed is not None: 120 | cell.collapsed = bool(collapsed) 121 | cell.metadata = NotebookNode(metadata or {}) 122 | 123 | return cell 124 | 125 | def new_text_cell(cell_type, source=None, rendered=None, metadata=None): 126 | """Create a new text cell.""" 127 | cell = NotebookNode() 128 | # VERSIONHACK: plaintext -> raw 129 | # handle never-released plaintext name for raw cells 130 | if cell_type == 'plaintext': 131 | cell_type = 'raw' 132 | if source is not None: 133 | cell.source = str(source) 134 | if rendered is not None: 135 | cell.rendered = str(rendered) 136 | cell.metadata = NotebookNode(metadata or {}) 137 | cell.cell_type = cell_type 138 | return cell 139 | 140 | 141 | def new_heading_cell(source=None, rendered=None, level=1, metadata=None): 142 | """Create a new section cell with a given integer level.""" 143 | cell = NotebookNode() 144 | cell.cell_type = 'heading' 145 | if source is not None: 146 | cell.source = str(source) 147 | if rendered is not None: 148 | cell.rendered = str(rendered) 149 | cell.level = int(level) 150 | cell.metadata = NotebookNode(metadata or {}) 151 | return cell 152 | 153 | 154 | def new_worksheet(name=None, cells=None, metadata=None): 155 | """Create a worksheet by name with with a list of cells.""" 156 | ws = NotebookNode() 157 | if name is not None: 158 | ws.name = str(name) 159 | if cells is None: 160 | ws.cells = [] 161 | else: 162 | ws.cells = list(cells) 163 | ws.metadata = NotebookNode(metadata or {}) 164 | return ws 165 | 166 | 167 | def new_notebook(name=None, metadata=None, worksheets=None): 168 | """Create a notebook by name, id and a list of worksheets.""" 169 | nb = NotebookNode() 170 | nb.nbformat = nbformat 171 | nb.nbformat_minor = nbformat_minor 172 | if worksheets is None: 173 | nb.worksheets = [] 174 | else: 175 | nb.worksheets = list(worksheets) 176 | if metadata is None: 177 | nb.metadata = new_metadata() 178 | else: 179 | nb.metadata = NotebookNode(metadata) 180 | if name is not None: 181 | nb.metadata.name = str(name) 182 | return nb 183 | 184 | 185 | def new_metadata(name=None, authors=None, license=None, created=None, 186 | modified=None, gistid=None): 187 | """Create a new metadata node.""" 188 | metadata = NotebookNode() 189 | if name is not None: 190 | metadata.name = str(name) 191 | if authors is not None: 192 | metadata.authors = list(authors) 193 | if created is not None: 194 | metadata.created = str(created) 195 | if modified is not None: 196 | metadata.modified = str(modified) 197 | if license is not None: 198 | metadata.license = str(license) 199 | if gistid is not None: 200 | metadata.gistid = str(gistid) 201 | return metadata 202 | 203 | def new_author(name=None, email=None, affiliation=None, url=None): 204 | """Create a new author.""" 205 | author = NotebookNode() 206 | if name is not None: 207 | author.name = str(name) 208 | if email is not None: 209 | author.email = str(email) 210 | if affiliation is not None: 211 | author.affiliation = str(affiliation) 212 | if url is not None: 213 | author.url = str(url) 214 | return author 215 | 216 | -------------------------------------------------------------------------------- /external/nbformat3/nbjson.py: -------------------------------------------------------------------------------- 1 | """Read and write notebooks in JSON format. 2 | 3 | Authors: 4 | 5 | * Brian Granger 6 | """ 7 | 8 | #----------------------------------------------------------------------------- 9 | # Copyright (C) 2008-2011 The IPython Development Team 10 | # 11 | # Distributed under the terms of the BSD License. The full license is in 12 | # the file COPYING, distributed as part of this software. 13 | #----------------------------------------------------------------------------- 14 | 15 | #----------------------------------------------------------------------------- 16 | # Imports 17 | #----------------------------------------------------------------------------- 18 | 19 | import copy 20 | import json 21 | 22 | from .nbbase import from_dict 23 | from .rwbase import ( 24 | NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines 25 | ) 26 | 27 | from . import py3compat 28 | 29 | #----------------------------------------------------------------------------- 30 | # Code 31 | #----------------------------------------------------------------------------- 32 | 33 | class BytesEncoder(json.JSONEncoder): 34 | """A JSON encoder that accepts b64 (and other *ascii*) bytestrings.""" 35 | def default(self, obj): 36 | if isinstance(obj, bytes): 37 | return obj.decode('ascii') 38 | return json.JSONEncoder.default(self, obj) 39 | 40 | 41 | class JSONReader(NotebookReader): 42 | 43 | def reads(self, s, **kwargs): 44 | nb = json.loads(s, **kwargs) 45 | nb = self.to_notebook(nb, **kwargs) 46 | return nb 47 | 48 | def to_notebook(self, d, **kwargs): 49 | return restore_bytes(rejoin_lines(from_dict(d))) 50 | 51 | 52 | class JSONWriter(NotebookWriter): 53 | 54 | def writes(self, nb, **kwargs): 55 | kwargs['cls'] = BytesEncoder 56 | kwargs['indent'] = 1 57 | kwargs['sort_keys'] = True 58 | kwargs['separators'] = (',',': ') 59 | if kwargs.pop('split_lines', True): 60 | nb = split_lines(copy.deepcopy(nb)) 61 | return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8') 62 | 63 | 64 | _reader = JSONReader() 65 | _writer = JSONWriter() 66 | 67 | reads = _reader.reads 68 | read = _reader.read 69 | to_notebook = _reader.to_notebook 70 | write = _writer.write 71 | writes = _writer.writes 72 | 73 | -------------------------------------------------------------------------------- /external/nbformat3/nbpy.py: -------------------------------------------------------------------------------- 1 | """Read and write notebooks as regular .py files. 2 | 3 | Authors: 4 | 5 | * Brian Granger 6 | """ 7 | 8 | #----------------------------------------------------------------------------- 9 | # Copyright (C) 2008-2011 The IPython Development Team 10 | # 11 | # Distributed under the terms of the BSD License. The full license is in 12 | # the file COPYING, distributed as part of this software. 13 | #----------------------------------------------------------------------------- 14 | 15 | #----------------------------------------------------------------------------- 16 | # Imports 17 | #----------------------------------------------------------------------------- 18 | 19 | import re 20 | from .rwbase import NotebookReader, NotebookWriter 21 | from .nbbase import ( 22 | new_code_cell, new_text_cell, new_worksheet, 23 | new_notebook, new_heading_cell, nbformat, nbformat_minor, 24 | ) 25 | 26 | #----------------------------------------------------------------------------- 27 | # Code 28 | #----------------------------------------------------------------------------- 29 | 30 | _encoding_declaration_re = re.compile(r"^#.*coding[:=]\s*([-\w.]+)") 31 | 32 | class PyReaderError(Exception): 33 | pass 34 | 35 | 36 | class PyReader(NotebookReader): 37 | 38 | def reads(self, s, **kwargs): 39 | return self.to_notebook(s,**kwargs) 40 | 41 | def to_notebook(self, s, **kwargs): 42 | lines = s.splitlines() 43 | cells = [] 44 | cell_lines = [] 45 | kwargs = {} 46 | state = 'codecell' 47 | for line in lines: 48 | if line.startswith('# ') or _encoding_declaration_re.match(line): 49 | pass 50 | elif line.startswith('# '): 51 | cell = self.new_cell(state, cell_lines, **kwargs) 52 | if cell is not None: 53 | cells.append(cell) 54 | state = 'codecell' 55 | cell_lines = [] 56 | kwargs = {} 57 | elif line.startswith('# '): 58 | cell = self.new_cell(state, cell_lines, **kwargs) 59 | if cell is not None: 60 | cells.append(cell) 61 | state = 'htmlcell' 62 | cell_lines = [] 63 | kwargs = {} 64 | elif line.startswith('# '): 65 | cell = self.new_cell(state, cell_lines, **kwargs) 66 | if cell is not None: 67 | cells.append(cell) 68 | state = 'markdowncell' 69 | cell_lines = [] 70 | kwargs = {} 71 | # VERSIONHACK: plaintext -> raw 72 | elif line.startswith('# ') or line.startswith('# '): 73 | cell = self.new_cell(state, cell_lines, **kwargs) 74 | if cell is not None: 75 | cells.append(cell) 76 | state = 'rawcell' 77 | cell_lines = [] 78 | kwargs = {} 79 | elif line.startswith('# \d)>',line) 85 | if m is not None: 86 | state = 'headingcell' 87 | kwargs = {} 88 | kwargs['level'] = int(m.group('level')) 89 | else: 90 | state = 'codecell' 91 | kwargs = {} 92 | cell_lines = [] 93 | else: 94 | cell_lines.append(line) 95 | if cell_lines and state == 'codecell': 96 | cell = self.new_cell(state, cell_lines) 97 | if cell is not None: 98 | cells.append(cell) 99 | ws = new_worksheet(cells=cells) 100 | nb = new_notebook(worksheets=[ws]) 101 | return nb 102 | 103 | def new_cell(self, state, lines, **kwargs): 104 | if state == 'codecell': 105 | input = '\n'.join(lines) 106 | input = input.strip('\n') 107 | if input: 108 | return new_code_cell(input=input) 109 | elif state == 'htmlcell': 110 | text = self._remove_comments(lines) 111 | if text: 112 | return new_text_cell('html',source=text) 113 | elif state == 'markdowncell': 114 | text = self._remove_comments(lines) 115 | if text: 116 | return new_text_cell('markdown',source=text) 117 | elif state == 'rawcell': 118 | text = self._remove_comments(lines) 119 | if text: 120 | return new_text_cell('raw',source=text) 121 | elif state == 'headingcell': 122 | text = self._remove_comments(lines) 123 | level = kwargs.get('level',1) 124 | if text: 125 | return new_heading_cell(source=text,level=level) 126 | 127 | def _remove_comments(self, lines): 128 | new_lines = [] 129 | for line in lines: 130 | if line.startswith('#'): 131 | new_lines.append(line[2:]) 132 | else: 133 | new_lines.append(line) 134 | text = '\n'.join(new_lines) 135 | text = text.strip('\n') 136 | return text 137 | 138 | def split_lines_into_blocks(self, lines): 139 | if len(lines) == 1: 140 | yield lines[0] 141 | raise StopIteration() 142 | import ast 143 | source = '\n'.join(lines) 144 | code = ast.parse(source) 145 | starts = [x.lineno-1 for x in code.body] 146 | for i in range(len(starts)-1): 147 | yield '\n'.join(lines[starts[i]:starts[i+1]]).strip('\n') 148 | yield '\n'.join(lines[starts[-1]:]).strip('\n') 149 | 150 | 151 | class PyWriter(NotebookWriter): 152 | 153 | def writes(self, nb, **kwargs): 154 | lines = ['# -*- coding: utf-8 -*-'] 155 | lines.extend([ 156 | '# %i.%i' % (nbformat, nbformat_minor), 157 | '', 158 | ]) 159 | for ws in nb.worksheets: 160 | for cell in ws.cells: 161 | if cell.cell_type == 'code': 162 | input = cell.get('input') 163 | if input is not None: 164 | lines.extend(['# ','']) 165 | lines.extend(input.splitlines()) 166 | lines.append('') 167 | elif cell.cell_type == 'html': 168 | input = cell.get('source') 169 | if input is not None: 170 | lines.extend(['# ','']) 171 | lines.extend(['# ' + line for line in input.splitlines()]) 172 | lines.append('') 173 | elif cell.cell_type == 'markdown': 174 | input = cell.get('source') 175 | if input is not None: 176 | lines.extend(['# ','']) 177 | lines.extend(['# ' + line for line in input.splitlines()]) 178 | lines.append('') 179 | elif cell.cell_type == 'raw': 180 | input = cell.get('source') 181 | if input is not None: 182 | lines.extend(['# ','']) 183 | lines.extend(['# ' + line for line in input.splitlines()]) 184 | lines.append('') 185 | elif cell.cell_type == 'heading': 186 | input = cell.get('source') 187 | level = cell.get('level',1) 188 | if input is not None: 189 | lines.extend(['# ' % level,'']) 190 | lines.extend(['# ' + line for line in input.splitlines()]) 191 | lines.append('') 192 | lines.append('') 193 | return str('\n'.join(lines)) 194 | 195 | 196 | _reader = PyReader() 197 | _writer = PyWriter() 198 | 199 | reads = _reader.reads 200 | read = _reader.read 201 | to_notebook = _reader.to_notebook 202 | write = _writer.write 203 | writes = _writer.writes 204 | 205 | -------------------------------------------------------------------------------- /external/nbformat3/py3compat.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """Compatibility tricks for Python 3. Mainly to do with unicode.""" 3 | import builtins 4 | import functools 5 | import sys 6 | import re 7 | import types 8 | 9 | from .encoding import DEFAULT_ENCODING 10 | 11 | orig_open = open 12 | 13 | def no_code(x, encoding=None): 14 | return x 15 | 16 | def decode(s, encoding=None): 17 | encoding = encoding or DEFAULT_ENCODING 18 | return s.decode(encoding, "replace") 19 | 20 | def encode(u, encoding=None): 21 | encoding = encoding or DEFAULT_ENCODING 22 | return u.encode(encoding, "replace") 23 | 24 | 25 | def cast_unicode(s, encoding=None): 26 | if isinstance(s, bytes): 27 | return decode(s, encoding) 28 | return s 29 | 30 | def cast_bytes(s, encoding=None): 31 | if not isinstance(s, bytes): 32 | return encode(s, encoding) 33 | return s 34 | 35 | def _modify_str_or_docstring(str_change_func): 36 | @functools.wraps(str_change_func) 37 | def wrapper(func_or_str): 38 | if isinstance(func_or_str, str): 39 | func = None 40 | doc = func_or_str 41 | else: 42 | func = func_or_str 43 | doc = func.__doc__ 44 | 45 | doc = str_change_func(doc) 46 | 47 | if func: 48 | func.__doc__ = doc 49 | return func 50 | return doc 51 | return wrapper 52 | 53 | if sys.version_info[0] >= 3: 54 | PY3 = True 55 | 56 | input = input 57 | builtin_mod_name = "builtins" 58 | 59 | str_to_unicode = no_code 60 | unicode_to_str = no_code 61 | str_to_bytes = encode 62 | bytes_to_str = decode 63 | cast_bytes_py2 = no_code 64 | 65 | string_types = (str,) 66 | 67 | def isidentifier(s, dotted=False): 68 | if dotted: 69 | return all(isidentifier(a) for a in s.split(".")) 70 | return s.isidentifier() 71 | 72 | open = orig_open 73 | 74 | MethodType = types.MethodType 75 | 76 | def execfile(fname, glob, loc=None): 77 | loc = loc if (loc is not None) else glob 78 | with open(fname, 'rb') as f: 79 | exec(compile(f.read(), fname, 'exec'), glob, loc) 80 | 81 | # Refactor print statements in doctests. 82 | _print_statement_re = re.compile(r"\bprint (?P.*)$", re.MULTILINE) 83 | def _print_statement_sub(match): 84 | expr = match.groups('expr') 85 | return "print(%s)" % expr 86 | 87 | @_modify_str_or_docstring 88 | def doctest_refactor_print(doc): 89 | """Refactor 'print x' statements in a doctest to print(x) style. 2to3 90 | unfortunately doesn't pick up on our doctests. 91 | 92 | Can accept a string or a function, so it can be used as a decorator.""" 93 | return _print_statement_re.sub(_print_statement_sub, doc) 94 | 95 | # Abstract u'abc' syntax: 96 | @_modify_str_or_docstring 97 | def u_format(s): 98 | """"{u}'abc'" --> "'abc'" (Python 3) 99 | 100 | Accepts a string or a function, so it can be used as a decorator.""" 101 | return s.format(u='') 102 | 103 | else: 104 | PY3 = False 105 | 106 | input = raw_input 107 | builtin_mod_name = "__builtin__" 108 | 109 | str_to_unicode = decode 110 | unicode_to_str = encode 111 | str_to_bytes = no_code 112 | bytes_to_str = no_code 113 | cast_bytes_py2 = cast_bytes 114 | 115 | string_types = (str, str) 116 | 117 | import re 118 | _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$") 119 | def isidentifier(s, dotted=False): 120 | if dotted: 121 | return all(isidentifier(a) for a in s.split(".")) 122 | return bool(_name_re.match(s)) 123 | 124 | class open(object): 125 | """Wrapper providing key part of Python 3 open() interface.""" 126 | def __init__(self, fname, mode="r", encoding="utf-8"): 127 | self.f = orig_open(fname, mode) 128 | self.enc = encoding 129 | 130 | def write(self, s): 131 | return self.f.write(s.encode(self.enc)) 132 | 133 | def read(self, size=-1): 134 | return self.f.read(size).decode(self.enc) 135 | 136 | def close(self): 137 | return self.f.close() 138 | 139 | def __enter__(self): 140 | return self 141 | 142 | def __exit__(self, etype, value, traceback): 143 | self.f.close() 144 | 145 | def MethodType(func, instance): 146 | return types.MethodType(func, instance, type(instance)) 147 | 148 | # don't override system execfile on 2.x: 149 | execfile = execfile 150 | 151 | def doctest_refactor_print(func_or_str): 152 | return func_or_str 153 | 154 | 155 | # Abstract u'abc' syntax: 156 | @_modify_str_or_docstring 157 | def u_format(s): 158 | """"{u}'abc'" --> "u'abc'" (Python 2) 159 | 160 | Accepts a string or a function, so it can be used as a decorator.""" 161 | return s.format(u='u') 162 | 163 | if sys.platform == 'win32': 164 | def execfile(fname, glob=None, loc=None): 165 | loc = loc if (loc is not None) else glob 166 | # The rstrip() is necessary b/c trailing whitespace in files will 167 | # cause an IndentationError in Python 2.6 (this was fixed in 2.7, 168 | # but we still support 2.6). See issue 1027. 169 | scripttext = builtins.open(fname).read().rstrip() + '\n' 170 | # compile converts unicode filename to str assuming 171 | # ascii. Let's do the conversion before calling compile 172 | if isinstance(fname, str): 173 | filename = unicode_to_str(fname) 174 | else: 175 | filename = fname 176 | exec(compile(scripttext, filename, 'exec'), glob, loc) 177 | else: 178 | def execfile(fname, *where): 179 | if isinstance(fname, str): 180 | filename = fname.encode(sys.getfilesystemencoding()) 181 | else: 182 | filename = fname 183 | builtins.execfile(filename, *where) 184 | -------------------------------------------------------------------------------- /external/nbformat3/rwbase.py: -------------------------------------------------------------------------------- 1 | """Base classes and utilities for readers and writers. 2 | 3 | Authors: 4 | 5 | * Brian Granger 6 | """ 7 | 8 | #----------------------------------------------------------------------------- 9 | # Copyright (C) 2008-2011 The IPython Development Team 10 | # 11 | # Distributed under the terms of the BSD License. The full license is in 12 | # the file COPYING, distributed as part of this software. 13 | #----------------------------------------------------------------------------- 14 | 15 | #----------------------------------------------------------------------------- 16 | # Imports 17 | #----------------------------------------------------------------------------- 18 | 19 | from base64 import encodestring, decodestring 20 | import pprint 21 | 22 | from . import py3compat 23 | 24 | str_to_bytes = py3compat.str_to_bytes 25 | 26 | #----------------------------------------------------------------------------- 27 | # Code 28 | #----------------------------------------------------------------------------- 29 | 30 | def restore_bytes(nb): 31 | """Restore bytes of image data from unicode-only formats. 32 | 33 | Base64 encoding is handled elsewhere. Bytes objects in the notebook are 34 | always b64-encoded. We DO NOT encode/decode around file formats. 35 | """ 36 | for ws in nb.worksheets: 37 | for cell in ws.cells: 38 | if cell.cell_type == 'code': 39 | for output in cell.outputs: 40 | if 'png' in output: 41 | output.png = str_to_bytes(output.png, 'ascii') 42 | if 'jpeg' in output: 43 | output.jpeg = str_to_bytes(output.jpeg, 'ascii') 44 | return nb 45 | 46 | # output keys that are likely to have multiline values 47 | _multiline_outputs = ['text', 'html', 'svg', 'latex', 'javascript', 'json'] 48 | 49 | 50 | # FIXME: workaround for old splitlines() 51 | def _join_lines(lines): 52 | """join lines that have been written by splitlines() 53 | 54 | Has logic to protect against `splitlines()`, which 55 | should have been `splitlines(True)` 56 | """ 57 | if lines and lines[0].endswith(('\n', '\r')): 58 | # created by splitlines(True) 59 | return ''.join(lines) 60 | else: 61 | # created by splitlines() 62 | return '\n'.join(lines) 63 | 64 | 65 | def rejoin_lines(nb): 66 | """rejoin multiline text into strings 67 | 68 | For reversing effects of ``split_lines(nb)``. 69 | 70 | This only rejoins lines that have been split, so if text objects were not split 71 | they will pass through unchanged. 72 | 73 | Used when reading JSON files that may have been passed through split_lines. 74 | """ 75 | for ws in nb.worksheets: 76 | for cell in ws.cells: 77 | if cell.cell_type == 'code': 78 | if 'input' in cell and isinstance(cell.input, list): 79 | cell.input = _join_lines(cell.input) 80 | for output in cell.outputs: 81 | for key in _multiline_outputs: 82 | item = output.get(key, None) 83 | if isinstance(item, list): 84 | output[key] = _join_lines(item) 85 | else: # text, heading cell 86 | for key in ['source', 'rendered']: 87 | item = cell.get(key, None) 88 | if isinstance(item, list): 89 | cell[key] = _join_lines(item) 90 | return nb 91 | 92 | 93 | def split_lines(nb): 94 | """split likely multiline text into lists of strings 95 | 96 | For file output more friendly to line-based VCS. ``rejoin_lines(nb)`` will 97 | reverse the effects of ``split_lines(nb)``. 98 | 99 | Used when writing JSON files. 100 | """ 101 | for ws in nb.worksheets: 102 | for cell in ws.cells: 103 | if cell.cell_type == 'code': 104 | if 'input' in cell and isinstance(cell.input, str): 105 | cell.input = cell.input.splitlines(True) 106 | for output in cell.outputs: 107 | for key in _multiline_outputs: 108 | item = output.get(key, None) 109 | if isinstance(item, str): 110 | output[key] = item.splitlines(True) 111 | else: # text, heading cell 112 | for key in ['source', 'rendered']: 113 | item = cell.get(key, None) 114 | if isinstance(item, str): 115 | cell[key] = item.splitlines(True) 116 | return nb 117 | 118 | # b64 encode/decode are never actually used, because all bytes objects in 119 | # the notebook are already b64-encoded, and we don't need/want to double-encode 120 | 121 | def base64_decode(nb): 122 | """Restore all bytes objects in the notebook from base64-encoded strings. 123 | 124 | Note: This is never used 125 | """ 126 | for ws in nb.worksheets: 127 | for cell in ws.cells: 128 | if cell.cell_type == 'code': 129 | for output in cell.outputs: 130 | if 'png' in output: 131 | if isinstance(output.png, str): 132 | output.png = output.png.encode('ascii') 133 | output.png = decodestring(output.png) 134 | if 'jpeg' in output: 135 | if isinstance(output.jpeg, str): 136 | output.jpeg = output.jpeg.encode('ascii') 137 | output.jpeg = decodestring(output.jpeg) 138 | return nb 139 | 140 | 141 | def base64_encode(nb): 142 | """Base64 encode all bytes objects in the notebook. 143 | 144 | These will be b64-encoded unicode strings 145 | 146 | Note: This is never used 147 | """ 148 | for ws in nb.worksheets: 149 | for cell in ws.cells: 150 | if cell.cell_type == 'code': 151 | for output in cell.outputs: 152 | if 'png' in output: 153 | output.png = encodestring(output.png).decode('ascii') 154 | if 'jpeg' in output: 155 | output.jpeg = encodestring(output.jpeg).decode('ascii') 156 | return nb 157 | 158 | 159 | class NotebookReader(object): 160 | """A class for reading notebooks.""" 161 | 162 | def reads(self, s, **kwargs): 163 | """Read a notebook from a string.""" 164 | raise NotImplementedError("loads must be implemented in a subclass") 165 | 166 | def read(self, fp, **kwargs): 167 | """Read a notebook from a file like object""" 168 | nbs = fp.read() 169 | if not py3compat.PY3 and not isinstance(nbs, str): 170 | nbs = py3compat.str_to_unicode(nbs) 171 | return self.reads(nbs, **kwargs) 172 | 173 | 174 | class NotebookWriter(object): 175 | """A class for writing notebooks.""" 176 | 177 | def writes(self, nb, **kwargs): 178 | """Write a notebook to a string.""" 179 | raise NotImplementedError("loads must be implemented in a subclass") 180 | 181 | def write(self, nb, fp, **kwargs): 182 | """Write a notebook to a file like object""" 183 | nbs = self.writes(nb,**kwargs) 184 | if not py3compat.PY3 and not isinstance(nbs, str): 185 | # this branch is likely only taken for JSON on Python 2 186 | nbs = py3compat.str_to_unicode(nbs) 187 | return fp.write(nbs) 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /external/websocket/__init__.py: -------------------------------------------------------------------------------- 1 | # from websocket import * 2 | -------------------------------------------------------------------------------- /ipy_connection.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2013, Maxim Grechkin 3 | # This file is licensed under GNU General Public License version 3 4 | # See COPYING for details. 5 | import json 6 | import uuid 7 | 8 | from time import sleep 9 | import threading 10 | import queue 11 | 12 | from collections import defaultdict 13 | 14 | import re 15 | import sys 16 | import _thread 17 | from .external import nbformat3 as nbformat 18 | from .external.websocket import websocket3 as websocket 19 | from .external.websocket.websocket3 import * 20 | from urllib.request import urlopen, Request, ProxyHandler, build_opener, install_opener, HTTPCookieProcessor 21 | from urllib.parse import urlparse, urlencode 22 | from http.cookiejar import CookieJar 23 | 24 | def install_proxy_opener(): 25 | global cookies 26 | cookies=CookieJar() 27 | proxy = ProxyHandler({}) 28 | opener = build_opener(proxy, HTTPCookieProcessor(cookies)) 29 | install_opener(opener) 30 | 31 | def create_uid(): 32 | return str(uuid.uuid4()) 33 | 34 | def get_notebooks(baseurl, psswd=None): 35 | try: 36 | if psswd!=None: 37 | target_url=baseurl+'''/login?next=%2F''' 38 | urlopen(target_url, data=urlencode({'password': psswd}).encode('utf8')) 39 | target_url = baseurl +"/notebooks" 40 | req = urlopen(target_url) 41 | encoding = req.headers.get_content_charset() 42 | body = req.readall().decode(encoding) 43 | if '' in body: 44 | return 'psswd' 45 | data = json.loads(body) 46 | return data 47 | except Exception as e: 48 | print("Error during loading notebook list from ", target_url) 49 | print(e) 50 | return None 51 | 52 | def create_new_notebook(baseurl): 53 | try: 54 | req = urlopen(baseurl + "/new") 55 | encoding = req.headers.get_content_charset() 56 | body = req.readall().decode(encoding) 57 | import re 58 | match = re.search("data-notebook-id=(.*)", body) 59 | nbid = match.groups()[0] 60 | return nbid 61 | except : 62 | raise 63 | return None 64 | 65 | def convert_mime_types(obj, content): 66 | if not content: 67 | return obj 68 | 69 | if "text/plain" in content: 70 | obj.text = content["text/plain"] 71 | 72 | if "text/html" in content: 73 | obj.html = content["text/html"] 74 | 75 | if "image/svg+xml" in content: 76 | obj.svg = content["image/svg+xml"] 77 | 78 | if "image/png" in content: 79 | obj.png = content["image/png"] 80 | 81 | if "image/jpeg" in content: 82 | obj.jpeg = content["image/jpeg"] 83 | 84 | if "text/latex" in content: 85 | obj.latex = content["text/latex"] 86 | 87 | if "application/json" in content: 88 | obj.json = content["application/json"] 89 | 90 | if "application/javascript" in content: 91 | obj.javascript = content["application/javascript"] 92 | 93 | return obj 94 | 95 | 96 | class Notebook(object): 97 | def __init__(self, s): 98 | self._notebook = nbformat.reads_json(s) 99 | if len(self._notebook.worksheets) == 0: 100 | # probably have an empty notebook, create a worksheet 101 | self._notebook.worksheets.append(nbformat.new_worksheet(cells = [nbformat.new_code_cell(input="")])) 102 | self._cells = self._notebook.worksheets[0].cells 103 | self.notebook_view = None 104 | 105 | def __str__(self): 106 | return nbformat.writes_json(self._notebook) 107 | 108 | def get_cell(self, cell_index): 109 | return Cell(self._cells[cell_index]) 110 | 111 | @property 112 | def cell_count(self): 113 | return len(self._cells) 114 | 115 | def create_new_cell(self, position, cell_type): 116 | if cell_type == "code": 117 | new_cell = nbformat.new_code_cell(input="") 118 | elif (cell_type == "markdown") or (cell_type == "raw"): 119 | new_cell = nbformat.new_text_cell(cell_type, source="") 120 | 121 | if position < 0: 122 | position = len(self._cells) 123 | self._cells.insert(position, new_cell) 124 | return Cell(new_cell) 125 | 126 | def delete_cell(self, cell_index): 127 | del self._cells[cell_index] 128 | 129 | def name(): 130 | doc = "The name property." 131 | 132 | def fget(self): 133 | return self._notebook.metadata.name 134 | def fset(self, value): 135 | self._notebook.metadata.name = value 136 | return locals() 137 | name = property(**name()) 138 | 139 | 140 | MAX_OUTPUT_SIZE = 5000 141 | 142 | 143 | class Cell(object): 144 | def __init__(self, obj): 145 | self._cell = obj 146 | self.runnig = False 147 | self.cell_view = None 148 | 149 | @property 150 | def cell_type(self): 151 | return self._cell.cell_type 152 | 153 | def source(): 154 | doc = "The source property." 155 | 156 | def fget(self): 157 | if self.cell_type == "code": 158 | return "".join(self._cell.input) 159 | else: 160 | return "".join(self._cell.source) 161 | 162 | def fset(self, value): 163 | if self.cell_type == "code": 164 | self._cell.input = value 165 | else: 166 | self._cell.source = value 167 | return locals() 168 | source = property(**source()) 169 | 170 | @property 171 | def output(self): 172 | result = [] 173 | for output in self._cell.outputs: 174 | if "text" in output: 175 | result.append(output.text) 176 | elif "traceback" in output: 177 | data = "\n".join(output.traceback) 178 | data = re.sub("\x1b[^m]*m", "", data) # remove escape characters 179 | result.append(data) 180 | if not data.endswith("\n"): 181 | result.append("\n") 182 | result = "".join(result) 183 | if len(result) > MAX_OUTPUT_SIZE: 184 | result = result[:MAX_OUTPUT_SIZE] + "..." 185 | return result 186 | 187 | def on_output(self, msg_type, content): 188 | output = None 189 | content = defaultdict(lambda: None, content) # an easy way to avoid checking all parameters 190 | if msg_type == "stream": 191 | output = nbformat.new_output(msg_type, content["data"], stream=content["name"]) 192 | elif msg_type == "pyerr": 193 | output = nbformat.new_output(msg_type, traceback=content["traceback"], ename=content["ename"], evalue=content["evalue"]) 194 | elif msg_type == "pyout": 195 | output = nbformat.new_output(msg_type, prompt_number=content["prompt_number"]) 196 | convert_mime_types(output, content["data"]) 197 | elif msg_type == "display_data": 198 | output = nbformat.new_output(msg_type, prompt_number=content["prompt_number"]) 199 | convert_mime_types(output, content["data"]) 200 | else: 201 | raise Exception("Unknown msg_type") 202 | 203 | if output: 204 | self._cell.outputs.append(output) 205 | if self.cell_view: 206 | self.cell_view.update_output() 207 | 208 | def on_execute_reply(self, msg_id, content): 209 | self.running = False 210 | if 'execution_count' in content: 211 | self._cell.prompt_number = content['execution_count'] 212 | self.cell_view.on_execute_reply(msg_id, content) 213 | 214 | @property 215 | def prompt(self): 216 | if 'prompt_number' in self._cell: 217 | return str(self._cell.prompt_number) 218 | else: 219 | return " " 220 | 221 | def run(self, kernel): 222 | if self.cell_type != "code": 223 | return 224 | 225 | self._cell.prompt_number = '*' 226 | self._cell.outputs = [] 227 | if self.cell_view: 228 | self.cell_view.update_output() 229 | self.cell_view.update_prompt_number() 230 | 231 | kernel.run(self.source, output_callback=self.on_output, 232 | execute_reply_callback=self.on_execute_reply) 233 | 234 | 235 | output_msg_types = set(["stream", "display_data", "pyout", "pyerr"]) 236 | 237 | 238 | class Kernel(object): 239 | def __init__(self, notebook_id, baseurl): 240 | self.notebook_id = notebook_id 241 | self.session_id = create_uid() 242 | self.baseurl = baseurl 243 | self.shell = None 244 | self.iopub = None 245 | 246 | self.shell_messages = [] 247 | self.iopub_messages = [] 248 | self.running = False 249 | self.message_queue = queue.Queue() 250 | self.message_callbacks = dict() 251 | self.start_kernel() 252 | _thread.start_new_thread(self.process_messages, ()) 253 | self.status_callback = lambda x: None 254 | self.encoding = 'utf-8' 255 | 256 | @property 257 | def kernel_id(self): 258 | id = self.get_kernel_id() 259 | if id is None: 260 | self.start_kernel() 261 | return self.get_kernel_id() 262 | return id 263 | 264 | def get_kernel_id(self): 265 | notebooks = get_notebooks(self.baseurl) 266 | for nb in notebooks: 267 | if nb["notebook_id"] == self.notebook_id: 268 | return nb["kernel_id"] 269 | raise Exception("notebook_id not found") 270 | 271 | def start_kernel(self): 272 | url = self.baseurl + "/kernels?notebook=" + self.notebook_id 273 | req = urlopen(url, data=b"") # data="" makes it POST request 274 | req.read() 275 | self.create_websockets() 276 | 277 | def restart_kernel(self): 278 | url = self.baseurl + "/kernels/" + self.kernel_id + "/restart" 279 | req = urlopen(url, data=b"") 280 | req.read() 281 | self.create_websockets() 282 | self.status_callback("idle") 283 | 284 | def interrupt_kernel(self): 285 | url = self.baseurl + "/kernels/" + self.kernel_id + "/interrupt" 286 | req = urlopen(url, data=bytearray(b"")) 287 | req.read() 288 | 289 | def shutdown_kernel(self): 290 | url = self.baseurl + "/kernels/" + self.kernel_id 291 | req = Request(url) 292 | req.add_header("Content-Type", "application/json") 293 | req.get_method = lambda: "DELETE" 294 | data = urlopen(req) 295 | data.read() 296 | self.status_callback("closed") 297 | 298 | def get_notebook(self): 299 | req = urlopen(self.notebook_url) 300 | try: 301 | return Notebook(req.readall().decode(self.encoding)) 302 | except AttributeError: 303 | return Notebook(req.read()) 304 | 305 | @property 306 | def notebook_url(self): 307 | return self.baseurl + "/notebooks/" + self.notebook_id 308 | 309 | def save_notebook(self, notebook): 310 | request = Request(self.notebook_url, str(notebook).encode(self.encoding)) 311 | request.add_header("Content-Type", "application/json") 312 | request.get_method = lambda: "PUT" 313 | data = urlopen(request) 314 | data.read() 315 | 316 | def on_iopub_msg(self, msg): 317 | m = json.loads(msg) 318 | self.iopub_messages.append(m) 319 | self.message_queue.put(m) 320 | 321 | def on_shell_msg(self, msg): 322 | m = json.loads(msg) 323 | self.shell_messages.append(m) 324 | self.message_queue.put(m) 325 | 326 | def register_callbacks(self, msg_id, output_callback, 327 | clear_output_callback=None, 328 | execute_reply_callback=None, 329 | set_next_input_callback=None): 330 | callbacks = {"output": output_callback} 331 | if clear_output_callback: 332 | callbacks["clear_output"] = clear_output_callback 333 | if execute_reply_callback: 334 | callbacks["execute_reply"] = execute_reply_callback 335 | if set_next_input_callback: 336 | callbacks["set_next_input"] = set_next_input_callback 337 | 338 | self.message_callbacks[msg_id] = callbacks 339 | 340 | def process_messages(self): 341 | while True: 342 | m = self.message_queue.get() 343 | content = m["content"] 344 | msg_type = m["header"]["msg_type"] 345 | 346 | if ("parent_header" in m) and ("msg_id" in m["parent_header"]): 347 | parent_id = m["parent_header"]["msg_id"] 348 | else: 349 | parent_id = None 350 | 351 | if msg_type == "status": 352 | if "execution_state" in content: 353 | self.status_callback(content["execution_state"]) 354 | 355 | elif parent_id in self.message_callbacks: 356 | callbacks = self.message_callbacks[parent_id] 357 | cb = None 358 | if msg_type in output_msg_types: 359 | cb = callbacks["output"] 360 | elif (msg_type == "clear_output") and ("clear_output" in callbacks): 361 | cb = callbacks["clear_output"] 362 | elif (msg_type == "execute_reply") and ("execute_reply" in callbacks): 363 | cb = callbacks["execute_reply"] 364 | elif (msg_type == "set_next_input") and ("set_next_input" in callbacks): 365 | cb = callbacks["set_next_input"] 366 | elif (msg_type == "complete_reply") and ("complete_reply" in callbacks): 367 | cb = callbacks["complete_reply"] 368 | 369 | if cb: 370 | cb(msg_type, content) 371 | 372 | self.message_queue.task_done() 373 | 374 | def create_get_output_callback(self, callback): 375 | def grab_output(msg_type, content): 376 | if msg_type == "stream": 377 | callback(content["data"]) 378 | elif msg_type == "pyerr": 379 | data = "\n".join(content["traceback"]) 380 | data = re.sub("\x1b[^m]*m", "", data) # remove escape characters 381 | callback(data) 382 | elif msg_type == "pyout": 383 | callback(content["data"]["text/plain"]) 384 | elif msg_type == "display_data": 385 | callback(content["data"]["text/plain"]) 386 | 387 | return grab_output 388 | 389 | def create_websockets(self): 390 | if self.shell is not None: 391 | self.shell.close() 392 | 393 | if self.iopub is not None: 394 | self.iopub.close() 395 | 396 | url = self.baseurl.replace('http', 'ws') + "/kernels/" + self.kernel_id + "/" 397 | auth=''.join([c.name+'='+c.value for c in cookies]) 398 | self.shell = websocket.WebSocketApp(url=url + "shell", 399 | on_message=lambda ws, msg: self.on_shell_msg(msg), 400 | on_open=lambda ws: ws.send(auth), 401 | on_error=lambda ws, err: print(err)) 402 | self.iopub = websocket.WebSocketApp(url=url + "iopub", 403 | on_message=lambda ws, msg: self.on_iopub_msg(msg), 404 | on_open=lambda ws: ws.send(auth), 405 | on_error=lambda ws, err: print(err)) 406 | 407 | _thread.start_new_thread(self.shell.run_forever, ()) 408 | _thread.start_new_thread(self.iopub.run_forever, ()) 409 | sleep(1) 410 | self.running = True 411 | 412 | def create_message(self, msg_type, content): 413 | msg = dict( 414 | header=dict( 415 | msg_type=msg_type, 416 | username="username", 417 | session=self.session_id, 418 | msg_id=create_uid()), 419 | content=content, 420 | parent_header={}, 421 | metadata={}) 422 | return msg 423 | 424 | def send_shell(self, msg): 425 | if not self.running: 426 | self.create_websockets() 427 | self.shell.send(json.dumps(msg)) 428 | 429 | def get_completitions(self, line, cursor_pos, text="", timeout=1): 430 | msg = self.create_message("complete_request", 431 | dict(line=line, cursor_pos=cursor_pos, text=text)) 432 | msg_id = msg["header"]["msg_id"] 433 | ev = threading.Event() 434 | matches = [] 435 | 436 | def callback(msg_id, content): 437 | if "matches" in content: 438 | matches[:] = content["matches"][:] 439 | ev.set() 440 | callbacks = {"complete_reply": callback} 441 | self.message_callbacks[msg_id] = callbacks 442 | self.send_shell(msg) 443 | ev.wait(timeout) 444 | del self.message_callbacks[msg_id] 445 | return matches 446 | 447 | def run(self, code, output_callback, 448 | clear_output_callback=None, 449 | execute_reply_callback=None, 450 | set_next_input_callback=None): 451 | msg = self.create_message("execute_request", 452 | dict(code=code, silent=False, 453 | user_variables=[], user_expressions={}, 454 | allow_stdin=False)) 455 | 456 | msg_id = msg["header"]["msg_id"] 457 | self.register_callbacks(msg_id, 458 | output_callback, 459 | clear_output_callback, 460 | execute_reply_callback, 461 | set_next_input_callback) 462 | self.send_shell(msg) 463 | -------------------------------------------------------------------------------- /ipy_view.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2013, Maxim Grechkin 3 | # This file is licensed under GNU General Public License version 3 4 | # See COPYING for details. 5 | from __future__ import print_function 6 | import sublime 7 | from . import ipy_connection 8 | import re 9 | 10 | 11 | 12 | def create_kernel(baseurl, notebook_id): 13 | return ipy_connection.Kernel(notebook_id, baseurl) 14 | 15 | output_draw_style = sublime.HIDDEN 16 | input_draw_style = sublime.HIDDEN 17 | cell_draw_style = sublime.HIDDEN 18 | 19 | 20 | class BaseCellView(object): 21 | def __init__(self, index, view, cell): 22 | self.index = index 23 | self.view = view 24 | self.cell = cell 25 | self.cell.cell_view = self 26 | self.buffer_ready = False 27 | self.owned_regions = ["inb_input"] 28 | 29 | def get_cell_region(self): 30 | try: 31 | reg = self.view.get_regions("inb_cells")[self.index] 32 | return sublime.Region(reg.a+1, reg.b) 33 | except IndexError: 34 | return None 35 | 36 | def run(self, kernel, region): 37 | pass 38 | 39 | def get_region(self, regname): 40 | cell_reg = self.get_cell_region() 41 | if cell_reg is None: 42 | return None 43 | all_regs = self.view.get_regions(regname) 44 | for reg in all_regs: 45 | if cell_reg.contains(reg): 46 | res = sublime.Region(reg.a+1, reg.b-1) 47 | return res 48 | return None 49 | 50 | def get_input_region(self): 51 | return self.get_region("inb_input") 52 | 53 | def write_to_region(self, edit, regname, text): 54 | if text is None: 55 | return 56 | if text.endswith("\n"): 57 | text = text[:-1] 58 | region = self.get_region(regname) 59 | self.view.set_read_only(False) 60 | self.view.replace(edit, region, text) 61 | 62 | def select(self, last_line=False): 63 | input_region = self.get_input_region() 64 | if input_region is None: 65 | return 66 | 67 | if last_line: 68 | pos = self.view.line(input_region.b).a 69 | else: 70 | pos = input_region.a 71 | 72 | self.view.sel().clear() 73 | self.view.sel().add(sublime.Region(pos, pos)) 74 | self.view.show_at_center(pos) 75 | 76 | def setup(self, edit): 77 | self.buffer_ready = True 78 | 79 | def teardown(self, edit): 80 | cell_reg = self.get_cell_region() 81 | for regname in self.owned_regions: 82 | all_regs = self.view.get_regions(regname) 83 | all_regs = [reg for reg in all_regs if not cell_reg.contains(reg)] 84 | self.view.add_regions(regname, all_regs, "source.python", "", input_draw_style) 85 | self.view.erase(edit, sublime.Region(cell_reg.a, cell_reg.b-1)) 86 | 87 | def draw(self, edit): 88 | if not self.buffer_ready: 89 | self.setup(edit) 90 | 91 | def get_input_content(self): 92 | input_region = self.get_input_region() 93 | if input_region: 94 | return self.view.substr(input_region) 95 | else: 96 | return "" 97 | 98 | def check_R(self): 99 | pass 100 | 101 | 102 | class CodeCellView(BaseCellView): 103 | def __init__(self, nbview, index, view, cell): 104 | BaseCellView.__init__(self, index, view, cell) 105 | self.running = False 106 | self.nbview = nbview 107 | self.owned_regions.append("inb_output") 108 | self.old_is_R = self.is_R_cell() 109 | self.old_prompt_number = -1 110 | 111 | @property 112 | def prompt(self): 113 | return self.cell.prompt 114 | 115 | def run(self, kernel): 116 | if self.running: 117 | print("Warning") 118 | print("Cell is already running") 119 | return 120 | 121 | self.running = True 122 | code = self.get_code() 123 | self.cell.source = code 124 | self.cell.run(kernel) 125 | 126 | def setup(self, edit): 127 | BaseCellView.setup(self, edit) 128 | region = self.get_cell_region() 129 | start = region.a 130 | 131 | view = self.view 132 | 133 | self.view.set_read_only(False) 134 | 135 | start = start + view.insert(edit, start, self.get_input_prompt() % self.prompt) 136 | end = start + view.insert(edit, start, "\n\n") 137 | 138 | reg = sublime.Region(start, end) 139 | regs = view.get_regions("inb_input") 140 | regs.append(reg) 141 | view.add_regions("inb_input", regs, "source.python", "", input_draw_style) 142 | self.view.set_read_only(False) 143 | 144 | end = end + view.insert(edit, end, "#/Input[%s]\n\n#Output[%s]" % (self.prompt, self.prompt)) 145 | 146 | start = end 147 | end = start + view.insert(edit, start, "\n\n") 148 | 149 | reg = sublime.Region(start, end) 150 | regs = view.get_regions("inb_output") 151 | regs.append(reg) 152 | view.add_regions("inb_output", regs, "string", "", output_draw_style) 153 | self.view.set_read_only(False) 154 | 155 | end = end + view.insert(edit, end, "#/Output") 156 | 157 | def update_output(self): 158 | def run_command(): 159 | self.view.run_command("inb_insert_output", {"cell_index": self.index}) 160 | sublime.set_timeout(run_command, 0) 161 | 162 | def on_execute_reply(self, msg_id, content): 163 | self.running = False 164 | self.update_prompt_number() 165 | if "payload" in content: 166 | for p in content["payload"]: 167 | if (p["source"] == "IPython.zmq.page.page") or (p["source"] == "IPython.kernel.zmq.page.page"): 168 | self.nbview.on_pager(p["text"]) 169 | 170 | def update_prompt_number(self): 171 | def do_set(): 172 | self.view.run_command('rewrite_prompt_number', {"cell_index": self.index}) 173 | 174 | try: 175 | self.view.run_command('rewrite_prompt_number', {"cell_index": self.index}) 176 | except: 177 | sublime.set_timeout(do_set, 0) 178 | 179 | def get_input_prompt(self): 180 | if self.is_R_cell(): 181 | return "#Input-R[%s]" 182 | else: 183 | return "#Input[%s]" 184 | 185 | def is_R_cell(self): 186 | code = self.get_input_content() 187 | if code == "": 188 | code = self.cell.source 189 | return (len(code) >= 3) and (code[:3] == '%%R') 190 | 191 | def check_R(self): 192 | if self.old_is_R != self.is_R_cell(): 193 | self.update_prompt_number() 194 | 195 | def rewrite_prompt_number(self, edit): 196 | if (self.prompt == self.old_prompt_number) and (self.old_is_R == self.is_R_cell()): 197 | return 198 | 199 | self.old_prompt_number = self.prompt 200 | self.old_is_R = self.is_R_cell() 201 | 202 | inp_reg = self.get_input_region() 203 | line = self.view.line(inp_reg.begin() - 1) 204 | self.view.replace(edit, line, self.get_input_prompt() % self.prompt) 205 | 206 | inp_reg = self.get_input_region() 207 | line = self.view.line(inp_reg.end() + 2) 208 | self.view.replace(edit, line, "#/Input[%s]" % self.prompt) 209 | 210 | out_reg = self.get_region("inb_output") 211 | line = self.view.line(out_reg.begin() - 1) 212 | self.view.replace(edit, line, "#Output[%s]" % self.prompt) 213 | 214 | 215 | 216 | def output_result(self, edit): 217 | output = self.cell.output 218 | output = "\n".join(map(lambda s: " " + s, output.splitlines())) 219 | self.write_to_region(edit, "inb_output", output) 220 | 221 | def draw(self, edit): 222 | BaseCellView.draw(self, edit) 223 | self.write_to_region(edit, "inb_input", self.cell.source) 224 | self.output_result(edit) 225 | 226 | def get_code(self): 227 | return self.get_input_content() 228 | 229 | def update_code(self): 230 | self.cell.source = self.get_code() 231 | 232 | 233 | class TextCell(BaseCellView): 234 | def run(self, kernel): 235 | print("Cannot run Markdown cell") 236 | 237 | def get_cell_title(self): 238 | if self.cell.cell_type == "markdown": 239 | return "Markdown" 240 | elif self.cell.cell_type == "raw": 241 | return "Raw text" 242 | elif self.cell.cell_type == "heading": 243 | return "Heading" 244 | else: 245 | print("Unknwon cell type: " + str(self.cell.cell_type)) 246 | return "Unknown" 247 | 248 | def setup(self, edit): 249 | BaseCellView.setup(self, edit) 250 | region = self.get_cell_region() 251 | start = region.a 252 | 253 | view = self.view 254 | 255 | self.view.set_read_only(False) 256 | 257 | start = start + view.insert(edit, start, "#" + self.get_cell_title()) 258 | end = start + view.insert(edit, start, "\n\n") 259 | 260 | reg = sublime.Region(start, end) 261 | regs = view.get_regions("inb_input") 262 | regs.append(reg) 263 | view.add_regions("inb_input", regs, "source.python", "", input_draw_style) 264 | self.view.set_read_only(False) 265 | 266 | end = end + view.insert(edit, end, "#/" + self.get_cell_title()) 267 | 268 | def on_execute_reply(self, msg_id, content): 269 | raise Exception("Shouldn't get this") 270 | 271 | def draw(self, edit): 272 | BaseCellView.draw(self, edit) 273 | self.write_to_region(edit, "inb_input", self.cell.source) 274 | 275 | def get_source(self): 276 | return self.get_input_content() 277 | 278 | def update_code(self): 279 | self.cell.source = self.get_source() 280 | 281 | 282 | class NotebookView(object): 283 | def __init__(self, view, notebook_id, baseurl): 284 | self.view = view 285 | self.baseurl = baseurl 286 | view.set_scratch(True) 287 | #view.set_syntax_file("Packages/Python/Python.tmLanguage") 288 | view.set_syntax_file("Packages/IPython Notebook/SublimeIPythonNotebook.tmLanguage") 289 | view.settings().set("ipython_notebook", True) 290 | self.cells = [] 291 | self.notebook_id = notebook_id 292 | self.kernel = create_kernel(baseurl, notebook_id) 293 | self.kernel.status_callback = self.on_status 294 | self.on_status("idle") 295 | self.notebook = self.kernel.get_notebook() 296 | self.modified = False 297 | self.show_modified_status(False) 298 | 299 | self.set_name(self.notebook.name) 300 | 301 | 302 | def get_name(self): 303 | return self.notebook.name 304 | 305 | def set_name(self, new_name): 306 | self.notebook.name = new_name 307 | self.view.set_name("IPy Notebook - " + self.notebook.name) 308 | 309 | def get_cell_separator(self): 310 | return "\n\n" 311 | 312 | def on_sel_modified(self): 313 | readonly = True 314 | regset = self.view.get_regions("inb_input") 315 | 316 | first_cell_index = -1 317 | for s in self.view.sel(): 318 | readonly = True 319 | for i, reg in enumerate(regset): 320 | reg = sublime.Region(reg.begin()+1, reg.end()-1) 321 | if reg.contains(s): 322 | if first_cell_index < 0: 323 | first_cell_index = i 324 | readonly = False 325 | break 326 | if readonly: 327 | break 328 | 329 | if first_cell_index >= 0: 330 | self.highlight_cell(regset[first_cell_index]) 331 | else: 332 | self.view.erase_regions("inb_highlight") 333 | 334 | self.view.set_read_only(readonly) 335 | 336 | def show_modified_status(self, val): 337 | if val: 338 | state = "modified" 339 | else: 340 | state = "saved" 341 | 342 | def set_status(): 343 | self.view.set_status("NotebookStatus", "notebook: " + state) 344 | sublime.set_timeout(set_status, 0) 345 | 346 | def set_modified(self, new_val): 347 | if self.modified != new_val: 348 | self.show_modified_status(new_val) 349 | self.modified = new_val 350 | 351 | def on_modified(self): 352 | self.set_modified(True) 353 | 354 | regset = self.view.get_regions("inb_input") 355 | 356 | for s in self.view.sel(): 357 | for i, reg in enumerate(regset): 358 | reg = sublime.Region(reg.begin()+1, reg.end()-1) 359 | if reg.contains(s) and (i < len(self.cells)): 360 | self.cells[i].check_R() 361 | break 362 | 363 | def highlight_cell(self, input_region): 364 | reg = self.view.line(input_region.begin()-2) 365 | reg2 = self.view.line(input_region.end()+2) 366 | self.view.add_regions("inb_highlight", [reg, reg2], "ipynb.source.highlight", "", sublime.DRAW_EMPTY) 367 | 368 | def on_backspace(self): 369 | s = self.view.sel()[0] 370 | 371 | regset = self.view.get_regions("inb_input") 372 | for reg in regset: 373 | reg = sublime.Region(reg.begin()+2, reg.end()) 374 | if reg.contains(s): 375 | self.view.run_command("left_delete") 376 | return 377 | elif (reg.size() > 2) and (s.begin() == reg.begin() - 1) and (self.view.substr(s.begin()) == "\n"): 378 | self.view.run_command("left_delete") 379 | self.view.run_command("move", {"by": "characters", "forward": True}) 380 | return 381 | 382 | def add_cell(self, edit, start=-1): 383 | view = self.view 384 | if start < 0: 385 | start = view.size() 386 | 387 | self.view.set_read_only(False) 388 | start = start + view.insert(edit, start, self.get_cell_separator()) 389 | end = start + view.insert(edit, start, "\n\n") 390 | 391 | reg = sublime.Region(start, end) 392 | regs = view.get_regions("inb_cells") 393 | regs.append(reg) 394 | view.add_regions("inb_cells", regs, "", "", cell_draw_style) 395 | 396 | return reg 397 | 398 | def insert_cell_field(self, edit, pos=0): 399 | cell_regions = self.view.get_regions("inb_cells") 400 | assert len(self.cells) == len(cell_regions) 401 | 402 | if (pos < 0) or (pos > len(self.cells)): 403 | raise Exception("Wrong position to insert cell field") 404 | 405 | if pos > 0: 406 | pos = cell_regions[pos-1].b 407 | 408 | self.add_cell(edit, start=pos) 409 | 410 | def run_cell(self, edit, inplace): 411 | cell_index = self.get_current_cell_index() 412 | if cell_index < 0: 413 | return 414 | 415 | cell = self.get_cell_by_index(cell_index) 416 | if not cell: 417 | raise Exception("Cell not found") 418 | if not inplace: 419 | if cell_index == len(self.cells) - 1: 420 | self.insert_cell_at_position(edit, cell_index + 1) 421 | cell.run(self.kernel) 422 | if not inplace: 423 | self.move_to_cell(False) 424 | 425 | def get_cell_by_index(self, cell_index): 426 | res = self.cells[cell_index] 427 | res.view = self.view 428 | return res 429 | 430 | def get_current_cell_index(self): 431 | sel = self.view.sel() 432 | if len(sel) > 1: 433 | return -1 434 | sel = self.view.sel()[0] 435 | regions = self.view.get_regions("inb_cells") 436 | return self.find_cell_by_selection(sel, regions) 437 | 438 | def find_cell_by_selection(self, sel, regions): 439 | for i, reg in enumerate(regions): 440 | if reg.contains(sel): 441 | return i 442 | return -1 443 | 444 | def save_notebook(self): 445 | self.kernel.save_notebook(self.notebook) 446 | self.set_modified(False) 447 | 448 | def render_notebook(self, edit): 449 | self.cells = [] 450 | self.view.erase_regions("inb_cells") 451 | self.view.erase_regions("inb_input") 452 | self.view.erase_regions("inb_output") 453 | for i in range(self.notebook.cell_count): 454 | self.insert_cell_field(edit, i) 455 | cell = self.notebook.get_cell(i) 456 | cell_view = self.create_cell_view(i, self.view, cell) 457 | self.cells.append(cell_view) 458 | 459 | regions = self.view.get_regions("inb_cells") 460 | assert len(self.cells) == len(regions) 461 | 462 | for cell in self.cells: 463 | cell.draw(edit) 464 | 465 | if len(self.cells) > 0: 466 | self.cells[0].select() 467 | 468 | sublime.set_timeout(lambda : self.set_modified(False), 0) 469 | 470 | def update_notebook_from_buffer(self): 471 | for cell in self.cells: 472 | cell.update_code() 473 | 474 | def restart_kernel(self): 475 | for cell in self.cells: 476 | if isinstance(cell, CodeCellView): 477 | cell.running = False 478 | self.kernel.restart_kernel() 479 | 480 | def shutdown_kernel(self): 481 | for cell in self.cells: 482 | if isinstance(cell, CodeCellView): 483 | cell.running = False 484 | self.kernel.shutdown_kernel() 485 | 486 | def on_status(self, execution_state): 487 | def set_status(): 488 | self.view.set_status("ExecutionStatus", "kernel: " + execution_state) 489 | sublime.set_timeout(set_status, 0) 490 | 491 | def handle_completions(self, view, prefix, locations): 492 | cell_index = self.get_current_cell_index() 493 | if cell_index < 0: 494 | return None 495 | if not isinstance(self.cells[cell_index], CodeCellView): 496 | return None 497 | sel = view.sel() 498 | if len(sel) > 1: 499 | return [] 500 | sel = sel[0] 501 | line = view.substr(view.line(sel)) 502 | row, col = view.rowcol(sel.begin()) 503 | compl = self.kernel.get_completitions(line, col, timeout=0.7) 504 | 505 | 506 | if len(compl) > 0: 507 | def get_last_word(s): # needed for file/directory completion 508 | if s.endswith("/"): 509 | s = s[:-1] 510 | res = s.split("/")[-1] 511 | return res 512 | 513 | return ([(s + "\t (IPython)", get_last_word(s)) for s in compl], sublime.INHIBIT_EXPLICIT_COMPLETIONS | sublime.INHIBIT_WORD_COMPLETIONS) 514 | else: 515 | return None 516 | 517 | def delete_current_cell(self, edit): 518 | cell_index = self.get_current_cell_index() 519 | if cell_index < 0: 520 | return 521 | 522 | self.update_notebook_from_buffer() 523 | self.notebook.delete_cell(cell_index) 524 | self.cells[cell_index].teardown(edit) 525 | del self.cells[cell_index] 526 | for cell in self.cells: 527 | if cell.index >= cell_index: 528 | cell.index -= 1 529 | 530 | regions = self.view.get_regions("inb_cells") 531 | reg = regions[cell_index] 532 | self.view.erase(edit, self.view.full_line(sublime.Region(reg.a, reg.b-1))) 533 | regions = self.view.get_regions("inb_cells") 534 | del regions[cell_index] 535 | self.view.add_regions("inb_cells", regions, "", "", cell_draw_style) 536 | new_cell_index = cell_index - 1 if cell_index > 0 else 0 537 | self.cells[new_cell_index].select() 538 | 539 | def insert_cell_below(self, edit): 540 | cell_index = self.get_current_cell_index() 541 | if cell_index < 0: 542 | return 543 | 544 | self.insert_cell_at_position(edit, cell_index + 1) 545 | 546 | def insert_cell_above(self, edit): 547 | cell_index = self.get_current_cell_index() 548 | if cell_index < 0: 549 | return 550 | 551 | self.insert_cell_at_position(edit, cell_index) 552 | 553 | def insert_cell_at_position(self, edit, cell_index): 554 | self.update_notebook_from_buffer() 555 | for cell in self.cells: 556 | if cell.index >= cell_index: 557 | cell.index += 1 558 | 559 | new_cell = self.notebook.create_new_cell(cell_index, "code") 560 | new_view = self.create_cell_view(cell_index, self.view, new_cell) 561 | self.insert_cell_field(edit, cell_index) 562 | self.cells.insert(cell_index, new_view) 563 | new_view.draw(edit) 564 | new_view.select() 565 | 566 | def move_up(self): 567 | cell_index = self.get_current_cell_index() 568 | if cell_index < 0: 569 | return False 570 | else: 571 | sel = self.view.sel()[0].begin() 572 | reg = self.cells[cell_index].get_input_region() 573 | if self.view.line(reg.begin()) == self.view.line(sel): 574 | if cell_index > 0: 575 | self.cells[cell_index-1].select(last_line=True) 576 | return True 577 | return False 578 | 579 | def move_down(self): 580 | cell_index = self.get_current_cell_index() 581 | if cell_index < 0: 582 | return False 583 | else: 584 | sel = self.view.sel()[0].begin() 585 | reg = self.cells[cell_index].get_input_region() 586 | if self.view.line(reg.end()) == self.view.line(sel): 587 | if cell_index < len(self.cells) - 1: 588 | self.cells[cell_index+1].select() 589 | return True 590 | return False 591 | 592 | def move_left(self): 593 | cell_index = self.get_current_cell_index() 594 | if cell_index < 0: 595 | return False 596 | else: 597 | sel = self.view.sel()[0].begin() 598 | reg = self.cells[cell_index].get_input_region() 599 | if sel == reg.begin(): 600 | return True 601 | return False 602 | 603 | def move_right(self): 604 | cell_index = self.get_current_cell_index() 605 | if cell_index < 0: 606 | return False 607 | else: 608 | sel = self.view.sel()[0].begin() 609 | reg = self.cells[cell_index].get_input_region() 610 | if sel == reg.end(): 611 | return True 612 | return False 613 | 614 | def change_current_cell_type(self, edit, new_type): 615 | cell_index = self.get_current_cell_index() 616 | if cell_index < 0: 617 | return 618 | 619 | if self.cells[cell_index].cell.cell_type == new_type: 620 | return 621 | 622 | src = self.cells[cell_index].get_input_content() 623 | self.notebook.delete_cell(cell_index) 624 | new_cell = self.notebook.create_new_cell(cell_index, new_type) 625 | new_cell.source = src 626 | new_view = self.create_cell_view(cell_index, self.view, new_cell) 627 | self.cells[cell_index].teardown(edit) 628 | self.cells[cell_index] = new_view 629 | new_view.draw(edit) 630 | new_view.select() 631 | 632 | def create_cell_view(self, index, view, cell): 633 | if cell.cell_type == "code": 634 | return CodeCellView(self, index, view, cell) 635 | else: 636 | return TextCell(index, view, cell) 637 | 638 | def on_pager(self, text): 639 | text = re.sub("\x1b[^m]*m", "", text) 640 | def do_run(): 641 | self.view.run_command('set_pager_text', {'text': text}) 642 | try: 643 | self.view.run_command('set_pager_text', {'text': text}) 644 | except: 645 | sublime.set_timeout(do_run, 0) 646 | 647 | 648 | def move_to_cell(self, up): 649 | cell_index = self.get_current_cell_index() 650 | if cell_index < 0: 651 | return 652 | 653 | if up and cell_index > 0: 654 | self.cells[cell_index - 1].select(True) 655 | elif not up and (cell_index < len(self.cells) - 1): 656 | self.cells[cell_index + 1].select() 657 | 658 | 659 | class NotebookViewManager(object): 660 | def __init__(self): 661 | self.views = {} 662 | 663 | def create_nb_view(self, view, notebook_id, baseurl): 664 | id = view.id() 665 | nbview = NotebookView(view, notebook_id, baseurl) 666 | self.views[id] = nbview 667 | return nbview 668 | 669 | def get_nb_view(self, view): 670 | id = view.id() 671 | if id not in self.views: 672 | return None 673 | nbview = self.views[id] 674 | nbview.view = view 675 | return nbview 676 | 677 | def on_close(self, view): 678 | id = view.id() 679 | if id in self.views: 680 | del self.views[id] 681 | 682 | manager = NotebookViewManager() 683 | -------------------------------------------------------------------------------- /ipynb.hidden-tmTheme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | IPython Notebook theme (based on Monokai Bright) 7 | settings 8 | 9 | 10 | settings 11 | 12 | background 13 | #272822 14 | caret 15 | #F8F8F0 16 | foreground 17 | #F8F8F2 18 | invisibles 19 | #3B3A32 20 | lineHighlight 21 | #3E3D32 22 | selection 23 | #9D550F 24 | selectionForeground 25 | #fffff8 26 | inactiveSelection 27 | #bbbbbb 28 | inactiveSelectionForeground 29 | #222222 30 | findHighlight 31 | #FFE792 32 | findHighlightForeground 33 | #000000 34 | activeGuide 35 | #9D550FB0 36 | 37 | bracketsForeground 38 | #F8F8F2A5 39 | bracketsOptions 40 | underline 41 | 42 | bracketContentsForeground 43 | #F8F8F2A5 44 | bracketContentsOptions 45 | underline 46 | 47 | tagsOptions 48 | stippled_underline 49 | 50 | 51 | 52 | name 53 | Comment 54 | scope 55 | comment 56 | settings 57 | 58 | foreground 59 | #75715E 60 | 61 | 62 | 63 | name 64 | String 65 | scope 66 | string 67 | settings 68 | 69 | foreground 70 | #E6DB74 71 | 72 | 73 | 74 | name 75 | Number 76 | scope 77 | constant.numeric 78 | settings 79 | 80 | foreground 81 | #AE81FF 82 | 83 | 84 | 85 | name 86 | Built-in constant 87 | scope 88 | constant.language 89 | settings 90 | 91 | foreground 92 | #AE81FF 93 | 94 | 95 | 96 | name 97 | User-defined constant 98 | scope 99 | constant.character, constant.other 100 | settings 101 | 102 | foreground 103 | #AE81FF 104 | 105 | 106 | 107 | name 108 | Variable 109 | scope 110 | variable 111 | settings 112 | 113 | fontStyle 114 | 115 | 116 | 117 | 118 | name 119 | Keyword 120 | scope 121 | keyword 122 | settings 123 | 124 | foreground 125 | #F92672 126 | 127 | 128 | 129 | name 130 | Storage 131 | scope 132 | storage 133 | settings 134 | 135 | fontStyle 136 | 137 | foreground 138 | #F92672 139 | 140 | 141 | 142 | name 143 | Storage type 144 | scope 145 | storage.type 146 | settings 147 | 148 | fontStyle 149 | italic 150 | foreground 151 | #66D9EF 152 | 153 | 154 | 155 | name 156 | Class name 157 | scope 158 | entity.name.class 159 | settings 160 | 161 | fontStyle 162 | underline 163 | foreground 164 | #A6E22E 165 | 166 | 167 | 168 | name 169 | Inherited class 170 | scope 171 | entity.other.inherited-class 172 | settings 173 | 174 | fontStyle 175 | italic underline 176 | foreground 177 | #A6E22E 178 | 179 | 180 | 181 | name 182 | Function name 183 | scope 184 | entity.name.function 185 | settings 186 | 187 | fontStyle 188 | 189 | foreground 190 | #A6E22E 191 | 192 | 193 | 194 | name 195 | Function argument 196 | scope 197 | variable.parameter 198 | settings 199 | 200 | fontStyle 201 | italic 202 | foreground 203 | #FD971F 204 | 205 | 206 | 207 | name 208 | Tag name 209 | scope 210 | entity.name.tag 211 | settings 212 | 213 | fontStyle 214 | 215 | foreground 216 | #F92672 217 | 218 | 219 | 220 | name 221 | Tag attribute 222 | scope 223 | entity.other.attribute-name 224 | settings 225 | 226 | fontStyle 227 | 228 | foreground 229 | #A6E22E 230 | 231 | 232 | 233 | name 234 | Library function 235 | scope 236 | support.function 237 | settings 238 | 239 | fontStyle 240 | 241 | foreground 242 | #66D9EF 243 | 244 | 245 | 246 | name 247 | Library constant 248 | scope 249 | support.constant 250 | settings 251 | 252 | fontStyle 253 | 254 | foreground 255 | #66D9EF 256 | 257 | 258 | 259 | name 260 | Library class/type 261 | scope 262 | support.type, support.class 263 | settings 264 | 265 | fontStyle 266 | italic 267 | foreground 268 | #66D9EF 269 | 270 | 271 | 272 | name 273 | Library variable 274 | scope 275 | support.other.variable 276 | settings 277 | 278 | fontStyle 279 | 280 | 281 | 282 | 283 | name 284 | Invalid 285 | scope 286 | invalid 287 | settings 288 | 289 | background 290 | #F92672 291 | fontStyle 292 | 293 | foreground 294 | #F8F8F0 295 | 296 | 297 | 298 | name 299 | Invalid deprecated 300 | scope 301 | invalid.deprecated 302 | settings 303 | 304 | background 305 | #AE81FF 306 | foreground 307 | #F8F8F0 308 | 309 | 310 | 311 | name 312 | JSON String 313 | scope 314 | meta.structure.dictionary.json string.quoted.double.json 315 | settings 316 | 317 | foreground 318 | #CFCFC2 319 | 320 | 321 | 322 | 323 | name 324 | diff.header 325 | scope 326 | meta.diff, meta.diff.header 327 | settings 328 | 329 | foreground 330 | #75715E 331 | 332 | 333 | 334 | name 335 | diff.deleted 336 | scope 337 | markup.deleted 338 | settings 339 | 340 | foreground 341 | #F92672 342 | 343 | 344 | 345 | name 346 | diff.inserted 347 | scope 348 | markup.inserted 349 | settings 350 | 351 | foreground 352 | #A6E22E 353 | 354 | 355 | 356 | name 357 | diff.changed 358 | scope 359 | markup.changed 360 | settings 361 | 362 | foreground 363 | #E6DB74 364 | 365 | 366 | 367 | 368 | scope 369 | constant.numeric.line-number.find-in-files - match 370 | settings 371 | 372 | foreground 373 | #AE81FFA0 374 | 375 | 376 | 377 | scope 378 | entity.name.filename.find-in-files 379 | settings 380 | 381 | foreground 382 | #E6DB74 383 | 384 | 385 | 386 | name 387 | IPython Notebook Background 388 | scope 389 | -ipynb.source.input -ipynb.source.highlight 390 | settings 391 | 392 | background 393 | #373832 394 | 395 | 396 | 397 | 398 | name 399 | IPython Notebook Output 400 | scope 401 | ipynb.source.output 402 | settings 403 | 404 | background 405 | #374232 406 | 407 | 408 | 409 | 410 | uuid 411 | D8D5E82E-3D5B-46B5-238E-8C841C21347E 412 | 413 | 414 | -------------------------------------------------------------------------------- /ipynb_dark.hidden-tmTheme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | author 6 | Michael Sheets 7 | name 8 | Twilight 9 | settings 10 | 11 | 12 | settings 13 | 14 | background 15 | #141414 16 | caret 17 | #A7A7A7 18 | foreground 19 | #F8F8F8 20 | invisibles 21 | #FFFFFF40 22 | lineHighlight 23 | #FFFFFF08 24 | selection 25 | #DDF0FF33 26 | 27 | 28 | 29 | name 30 | Comment 31 | scope 32 | comment 33 | settings 34 | 35 | fontStyle 36 | italic 37 | foreground 38 | #5F5A60 39 | 40 | 41 | 42 | name 43 | Constant 44 | scope 45 | constant 46 | settings 47 | 48 | foreground 49 | #CF6A4C 50 | 51 | 52 | 53 | name 54 | Entity 55 | scope 56 | entity 57 | settings 58 | 59 | fontStyle 60 | 61 | foreground 62 | #9B703F 63 | 64 | 65 | 66 | name 67 | Keyword 68 | scope 69 | keyword 70 | settings 71 | 72 | fontStyle 73 | 74 | foreground 75 | #CDA869 76 | 77 | 78 | 79 | name 80 | Storage 81 | scope 82 | storage 83 | settings 84 | 85 | fontStyle 86 | 87 | foreground 88 | #F9EE98 89 | 90 | 91 | 92 | name 93 | String 94 | scope 95 | string 96 | settings 97 | 98 | fontStyle 99 | 100 | foreground 101 | #8F9D6A 102 | 103 | 104 | 105 | name 106 | Support 107 | scope 108 | support 109 | settings 110 | 111 | fontStyle 112 | 113 | foreground 114 | #9B859D 115 | 116 | 117 | 118 | name 119 | Variable 120 | scope 121 | variable 122 | settings 123 | 124 | foreground 125 | #7587A6 126 | 127 | 128 | 129 | name 130 | Invalid – Deprecated 131 | scope 132 | invalid.deprecated 133 | settings 134 | 135 | fontStyle 136 | italic underline 137 | foreground 138 | #D2A8A1 139 | 140 | 141 | 142 | name 143 | Invalid – Illegal 144 | scope 145 | invalid.illegal 146 | settings 147 | 148 | background 149 | #562D56BF 150 | foreground 151 | #F8F8F8 152 | 153 | 154 | 155 | name 156 | ----------------------------------- 157 | settings 158 | 159 | 160 | 161 | name 162 | ♦ Embedded Source 163 | scope 164 | text source 165 | settings 166 | 167 | background 168 | #B0B3BA14 169 | 170 | 171 | 172 | name 173 | ♦ Embedded Source (Bright) 174 | scope 175 | text.html.ruby source 176 | settings 177 | 178 | background 179 | #B1B3BA21 180 | 181 | 182 | 183 | name 184 | ♦ Entity inherited-class 185 | scope 186 | entity.other.inherited-class 187 | settings 188 | 189 | fontStyle 190 | italic 191 | foreground 192 | #9B5C2E 193 | 194 | 195 | 196 | name 197 | ♦ String embedded-source 198 | scope 199 | string source 200 | settings 201 | 202 | fontStyle 203 | 204 | foreground 205 | #DAEFA3 206 | 207 | 208 | 209 | name 210 | ♦ String constant 211 | scope 212 | string constant 213 | settings 214 | 215 | foreground 216 | #DDF2A4 217 | 218 | 219 | 220 | name 221 | ♦ String.regexp 222 | scope 223 | string.regexp 224 | settings 225 | 226 | fontStyle 227 | 228 | foreground 229 | #E9C062 230 | 231 | 232 | 233 | name 234 | ♦ String.regexp.«special» 235 | scope 236 | string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition 237 | settings 238 | 239 | foreground 240 | #CF7D34 241 | 242 | 243 | 244 | name 245 | ♦ String variable 246 | scope 247 | string variable 248 | settings 249 | 250 | foreground 251 | #8A9A95 252 | 253 | 254 | 255 | name 256 | ♦ Support.function 257 | scope 258 | support.function 259 | settings 260 | 261 | fontStyle 262 | 263 | foreground 264 | #DAD085 265 | 266 | 267 | 268 | name 269 | ♦ Support.constant 270 | scope 271 | support.constant 272 | settings 273 | 274 | fontStyle 275 | 276 | foreground 277 | #CF6A4C 278 | 279 | 280 | 281 | name 282 | c C/C++ Preprocessor Line 283 | scope 284 | meta.preprocessor.c 285 | settings 286 | 287 | foreground 288 | #8996A8 289 | 290 | 291 | 292 | name 293 | c C/C++ Preprocessor Directive 294 | scope 295 | meta.preprocessor.c keyword 296 | settings 297 | 298 | foreground 299 | #AFC4DB 300 | 301 | 302 | 303 | name 304 | ✘ Doctype/XML Processing 305 | scope 306 | meta.tag.sgml.doctype, meta.tag.sgml.doctype entity, meta.tag.sgml.doctype string, meta.tag.preprocessor.xml, meta.tag.preprocessor.xml entity, meta.tag.preprocessor.xml string 307 | settings 308 | 309 | foreground 310 | #494949 311 | 312 | 313 | 314 | name 315 | ✘ Meta.tag.«all» 316 | scope 317 | declaration.tag, declaration.tag entity, meta.tag, meta.tag entity 318 | settings 319 | 320 | foreground 321 | #AC885B 322 | 323 | 324 | 325 | name 326 | ✘ Meta.tag.inline 327 | scope 328 | declaration.tag.inline, declaration.tag.inline entity, source entity.name.tag, source entity.other.attribute-name, meta.tag.inline, meta.tag.inline entity 329 | settings 330 | 331 | foreground 332 | #E0C589 333 | 334 | 335 | 336 | name 337 | § css tag-name 338 | scope 339 | meta.selector.css entity.name.tag 340 | settings 341 | 342 | foreground 343 | #CDA869 344 | 345 | 346 | 347 | name 348 | § css:pseudo-class 349 | scope 350 | meta.selector.css entity.other.attribute-name.tag.pseudo-class 351 | settings 352 | 353 | foreground 354 | #8F9D6A 355 | 356 | 357 | 358 | name 359 | § css#id 360 | scope 361 | meta.selector.css entity.other.attribute-name.id 362 | settings 363 | 364 | foreground 365 | #8B98AB 366 | 367 | 368 | 369 | name 370 | § css.class 371 | scope 372 | meta.selector.css entity.other.attribute-name.class 373 | settings 374 | 375 | foreground 376 | #9B703F 377 | 378 | 379 | 380 | name 381 | § css property-name: 382 | scope 383 | support.type.property-name.css 384 | settings 385 | 386 | foreground 387 | #C5AF75 388 | 389 | 390 | 391 | name 392 | § css property-value; 393 | scope 394 | meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css 395 | settings 396 | 397 | foreground 398 | #F9EE98 399 | 400 | 401 | 402 | name 403 | § css @at-rule 404 | scope 405 | meta.preprocessor.at-rule keyword.control.at-rule 406 | settings 407 | 408 | foreground 409 | #8693A5 410 | 411 | 412 | 413 | name 414 | § css additional-constants 415 | scope 416 | meta.property-value support.constant.named-color.css, meta.property-value constant 417 | settings 418 | 419 | foreground 420 | #CA7840 421 | 422 | 423 | 424 | name 425 | § css constructor.argument 426 | scope 427 | meta.constructor.argument.css 428 | settings 429 | 430 | foreground 431 | #8F9D6A 432 | 433 | 434 | 435 | name 436 | ⎇ diff.header 437 | scope 438 | meta.diff, meta.diff.header, meta.separator 439 | settings 440 | 441 | background 442 | #0E2231 443 | fontStyle 444 | italic 445 | foreground 446 | #F8F8F8 447 | 448 | 449 | 450 | name 451 | ⎇ diff.deleted 452 | scope 453 | markup.deleted 454 | settings 455 | 456 | background 457 | #420E09 458 | foreground 459 | #F8F8F8 460 | 461 | 462 | 463 | name 464 | ⎇ diff.changed 465 | scope 466 | markup.changed 467 | settings 468 | 469 | background 470 | #4A410D 471 | foreground 472 | #F8F8F8 473 | 474 | 475 | 476 | name 477 | ⎇ diff.inserted 478 | scope 479 | markup.inserted 480 | settings 481 | 482 | background 483 | #253B22 484 | foreground 485 | #F8F8F8 486 | 487 | 488 | 489 | name 490 | Markup: List 491 | scope 492 | markup.list 493 | settings 494 | 495 | foreground 496 | #F9EE98 497 | 498 | 499 | 500 | name 501 | Markup: Heading 502 | scope 503 | markup.heading 504 | settings 505 | 506 | foreground 507 | #CF6A4C 508 | 509 | 510 | 511 | name 512 | IPython Notebook Background 513 | scope 514 | -ipynb.source.input -ipynb.source.highlight 515 | settings 516 | 517 | background 518 | #141414 519 | 520 | 521 | 522 | name 523 | IPython Notebook Output 524 | scope 525 | ipynb.source.output 526 | settings 527 | 528 | background 529 | #1F2F3A 530 | 531 | 532 | 533 | name 534 | IPython Notebook Invisible 535 | scope 536 | ipynb.source.invisible 537 | settings 538 | 539 | foreground 540 | #71ABD3 541 | 542 | 543 | 544 | uuid 545 | 766026CB-70AA-4610-B070-8DE07D967C5F 546 | 547 | 548 | -------------------------------------------------------------------------------- /ipynb_light.hidden-tmTheme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | author 6 | Jeroen van der Ham 7 | name 8 | iPlastic with modifications for IPython Notebook 9 | settings 10 | 11 | 12 | settings 13 | 14 | background 15 | #EEEEEEEB 16 | caret 17 | #000000 18 | foreground 19 | #000000 20 | invisibles 21 | #B3B3B3F4 22 | lineHighlight 23 | #0000001A 24 | selection 25 | #BAD6FD 26 | 27 | 28 | 29 | name 30 | String 31 | scope 32 | string 33 | settings 34 | 35 | foreground 36 | #009933 37 | 38 | 39 | 40 | name 41 | Number 42 | scope 43 | constant.numeric 44 | settings 45 | 46 | foreground 47 | #0066FF 48 | 49 | 50 | 51 | name 52 | Regular expression 53 | scope 54 | string.regexp 55 | settings 56 | 57 | foreground 58 | #FF0080 59 | 60 | 61 | 62 | name 63 | Keyword 64 | scope 65 | keyword 66 | settings 67 | 68 | foreground 69 | #0000FF 70 | 71 | 72 | 73 | name 74 | Identifier 75 | scope 76 | constant.language 77 | settings 78 | 79 | foreground 80 | #9700CC 81 | 82 | 83 | 84 | name 85 | Exception 86 | scope 87 | support.class.exception 88 | settings 89 | 90 | foreground 91 | #990000 92 | 93 | 94 | 95 | name 96 | Function name 97 | scope 98 | entity.name.function 99 | settings 100 | 101 | foreground 102 | #FF8000 103 | 104 | 105 | 106 | name 107 | Type name 108 | scope 109 | entity.name.type 110 | settings 111 | 112 | fontStyle 113 | bold underline 114 | 115 | 116 | 117 | name 118 | Arguments 119 | scope 120 | variable.parameter 121 | settings 122 | 123 | fontStyle 124 | italic 125 | 126 | 127 | 128 | name 129 | Comment 130 | scope 131 | comment 132 | settings 133 | 134 | fontStyle 135 | italic 136 | foreground 137 | #0066FF 138 | 139 | 140 | 141 | name 142 | Invalid 143 | scope 144 | invalid 145 | settings 146 | 147 | background 148 | #E71A114D 149 | foreground 150 | #FF0000 151 | 152 | 153 | 154 | name 155 | Trailing whitespace 156 | scope 157 | invalid.deprecated.trailing-whitespace 158 | settings 159 | 160 | background 161 | #E71A1100 162 | 163 | 164 | 165 | name 166 | Embedded source 167 | scope 168 | text source 169 | settings 170 | 171 | background 172 | #FAFAFAFC 173 | foreground 174 | #000000 175 | 176 | 177 | 178 | name 179 | Tag 180 | scope 181 | meta.tag, declaration.tag 182 | settings 183 | 184 | foreground 185 | #0033CC 186 | 187 | 188 | 189 | name 190 | Constant 191 | scope 192 | constant, support.constant 193 | settings 194 | 195 | foreground 196 | #6782D3 197 | 198 | 199 | 200 | name 201 | Support 202 | scope 203 | support 204 | settings 205 | 206 | fontStyle 207 | bold 208 | foreground 209 | #3333FF 210 | 211 | 212 | 213 | name 214 | Storage 215 | scope 216 | storage 217 | settings 218 | 219 | fontStyle 220 | bold 221 | 222 | 223 | 224 | name 225 | Section name 226 | scope 227 | entity.name.section 228 | settings 229 | 230 | fontStyle 231 | bold underline 232 | 233 | 234 | 235 | name 236 | Frame title 237 | scope 238 | entity.name.function.frame 239 | settings 240 | 241 | fontStyle 242 | bold 243 | foreground 244 | #000000 245 | 246 | 247 | 248 | name 249 | XML Declaration 250 | scope 251 | meta.tag.preprocessor.xml 252 | settings 253 | 254 | foreground 255 | #333333 256 | 257 | 258 | 259 | name 260 | Tag Attribute 261 | scope 262 | entity.other.attribute-name 263 | settings 264 | 265 | fontStyle 266 | italic 267 | foreground 268 | #3366CC 269 | 270 | 271 | 272 | name 273 | Tag Name 274 | scope 275 | entity.name.tag 276 | settings 277 | 278 | fontStyle 279 | bold 280 | 281 | 282 | 283 | 284 | name 285 | IPython Notebook Background 286 | scope 287 | -ipynb.source.input -ipynb.source.highlight 288 | settings 289 | 290 | background 291 | #FFFFFF 292 | 293 | 294 | 295 | 296 | name 297 | IPython Notebook Output 298 | scope 299 | ipynb.source.output 300 | settings 301 | 302 | background 303 | #F4FFF4 304 | 305 | 306 | 307 | 308 | name 309 | IPython Notebook Invisible 310 | scope 311 | ipynb.source.invisible 312 | settings 313 | 314 | foreground 315 | #EEEEEEEB 316 | 317 | 318 | 319 | uuid 320 | 4FCFA210-B247-11D9-9D11-000D93347A42 321 | 322 | 323 | -------------------------------------------------------------------------------- /subl_ipy_notebook.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2013, Maxim Grechkin 3 | # This file is licensed under GNU General Public License version 3 4 | # See COPYING for details. 5 | import sublime 6 | import sublime_plugin 7 | from . import ipy_view, ipy_connection 8 | 9 | 10 | manager = ipy_view.manager 11 | 12 | 13 | class SublimeINListener(sublime_plugin.EventListener): 14 | def on_selection_modified(self, view): 15 | nbview = manager.get_nb_view(view) 16 | if nbview: 17 | nbview.on_sel_modified() 18 | 19 | def on_modified(self, view): 20 | nbview = manager.get_nb_view(view) 21 | if nbview: 22 | nbview.on_modified() 23 | 24 | def on_close(self, view): 25 | manager.on_close(view) 26 | 27 | 28 | def get_last_used_address(): 29 | settings = sublime.load_settings("SublimeIPythonNotebook.sublime-settings") 30 | lst=settings.get("default_address", []) 31 | return lst if type(lst)==list else [lst] 32 | 33 | 34 | def set_last_used_address(value): 35 | settings = sublime.load_settings("SublimeIPythonNotebook.sublime-settings") 36 | addresses = get_last_used_address() 37 | if value in addresses: 38 | addresses.pop(addresses.index(value)) 39 | settings.set("default_address", [value]+addresses) 40 | sublime.save_settings("SublimeIPythonNotebook.sublime-settings") 41 | 42 | class InbPromptListNotebooksCommand(sublime_plugin.WindowCommand): 43 | def run(self): 44 | self.previous_addresses=get_last_used_address() 45 | if len(self.previous_addresses)==0: 46 | self.new_server() 47 | return 48 | self.previous_addresses += ["New Server"] 49 | self.window.show_quick_panel(self.previous_addresses, self.on_done) 50 | 51 | def new_server(self): 52 | self.window.show_input_panel("Notebook host:port : ", "http://127.0.0.1:8888", 53 | self.on_done, None, None) 54 | 55 | def on_done(self, line): 56 | if line==-1: 57 | return 58 | if type(line)==int: 59 | if line==len(self.previous_addresses)-1: 60 | self.new_server() 61 | else: 62 | self.window.run_command("inb_list_notebooks", {"baseurl": self.previous_addresses[line], "psswd": None}) 63 | else: 64 | self.window.run_command("inb_list_notebooks", {"baseurl": line, "psswd": None}) 65 | 66 | class InbPromptPasswordCommand(sublime_plugin.WindowCommand): 67 | def run(self, baseurl): 68 | self.baseurl=baseurl 69 | self.window.show_input_panel("Password: ", '', 70 | self.on_done, None, None) 71 | 72 | def on_done(self, line): 73 | self.window.run_command("inb_list_notebooks", {"baseurl": self.baseurl, 'psswd': line}) 74 | 75 | 76 | class InbListNotebooksCommand(sublime_plugin.WindowCommand): 77 | def run(self, baseurl, psswd): 78 | ipy_connection.install_proxy_opener() 79 | 80 | self.baseurl = baseurl 81 | nbs = ipy_connection.get_notebooks(baseurl, psswd) 82 | if nbs=='psswd': 83 | self.window.run_command("inb_prompt_password", {"baseurl": baseurl}) 84 | return 85 | if nbs is None: 86 | print("Cannot get a list of notebooks") 87 | return 88 | set_last_used_address(baseurl) 89 | self.nbs = nbs 90 | lst = ["0: Create New Notebook\n"] 91 | for i, nb in enumerate(nbs): 92 | lst.append(str(i+1) + ": " + nb["name"] + "\n") 93 | 94 | sublime.set_timeout(lambda: self.window.show_quick_panel(lst, self.on_done), 1) 95 | 96 | def on_done(self, picked): 97 | if picked == -1: 98 | return 99 | 100 | view = self.window.new_file() 101 | if picked > 0: 102 | manager.create_nb_view(view, self.nbs[picked-1]["notebook_id"], self.baseurl) 103 | else: 104 | new_nb_id = ipy_connection.create_new_notebook(self.baseurl) 105 | if new_nb_id is None: 106 | return 107 | manager.create_nb_view(view, new_nb_id, self.baseurl) 108 | 109 | view.run_command("inb_render_notebook") 110 | 111 | 112 | class SetPagerTextCommand(sublime_plugin.TextCommand): 113 | """command to set the text in the pop-up pager""" 114 | def run(self, edit, text): 115 | pager_view = self.view.window().get_output_panel("help") 116 | pager_view.insert(edit, 0, text) 117 | self.view.window().run_command("show_panel", {"panel": "output.help"}) 118 | 119 | 120 | class InbRestartKernelCommand(sublime_plugin.TextCommand): 121 | def run(self, edit): 122 | nbview = manager.get_nb_view(self.view) 123 | if nbview: 124 | nbview.restart_kernel() 125 | 126 | 127 | class InbInterruptKernelCommand(sublime_plugin.TextCommand): 128 | def run(self, edit): 129 | nbview = manager.get_nb_view(self.view) 130 | if nbview and nbview.kernel: 131 | nbview.kernel.interrupt_kernel() 132 | 133 | 134 | class InbSaveNotebookCommand(sublime_plugin.TextCommand): 135 | def run(self, edit): 136 | nbview = manager.get_nb_view(self.view) 137 | if nbview: 138 | nbview.update_notebook_from_buffer() 139 | nbview.save_notebook() 140 | 141 | def description(self): 142 | return "Save IPython notebook" 143 | 144 | class InbShutdownKernelCommand(sublime_plugin.TextCommand): 145 | def run(self, edit): 146 | nbview = manager.get_nb_view(self.view) 147 | if nbview and nbview.kernel: 148 | nbview.kernel.shutdown_kernel() 149 | 150 | class InbBackspaceCommand(sublime_plugin.TextCommand): 151 | def run(self, edit): 152 | nbview = manager.get_nb_view(self.view) 153 | if nbview: 154 | nbview.on_backspace() 155 | 156 | 157 | class InbClearBufferCommand(sublime_plugin.TextCommand): 158 | def run(self, edit): 159 | self.view.set_read_only(False) 160 | self.view.erase(edit, sublime.Region(0, self.view.size())) 161 | 162 | 163 | class InbRenderNotebookCommand(sublime_plugin.TextCommand): 164 | def run(self, edit): 165 | nbview = manager.get_nb_view(self.view) 166 | if nbview: 167 | self.view.set_read_only(False) 168 | self.view.erase(edit, sublime.Region(0, self.view.size())) 169 | nbview.render_notebook(edit) 170 | 171 | 172 | class InbInsertOutputCommand(sublime_plugin.TextCommand): 173 | def run(self, edit, cell_index): 174 | nbview = manager.get_nb_view(self.view) 175 | if not nbview: 176 | raise Exception("Failed to get NBView") 177 | 178 | cell = nbview.get_cell_by_index(cell_index) 179 | if not cell: 180 | raise Exception("Failed to get cell") 181 | 182 | cell.output_result(edit) 183 | 184 | 185 | class InbRunInNotebookCommand(sublime_plugin.TextCommand): 186 | def run(self, edit, inplace): 187 | nbview = manager.get_nb_view(self.view) 188 | if nbview: 189 | nbview.run_cell(edit, inplace) 190 | 191 | 192 | class InbDeleteCurrentCellCommand(sublime_plugin.TextCommand): 193 | def run(self, edit): 194 | nbview = manager.get_nb_view(self.view) 195 | if nbview: 196 | nbview.delete_current_cell(edit) 197 | 198 | 199 | class InbInsertCellAboveCommand(sublime_plugin.TextCommand): 200 | def run(self, edit): 201 | nbview = manager.get_nb_view(self.view) 202 | if nbview: 203 | nbview.insert_cell_above(edit) 204 | 205 | 206 | class InbInsertCellBelowCommand(sublime_plugin.TextCommand): 207 | def run(self, edit): 208 | nbview = manager.get_nb_view(self.view) 209 | if nbview: 210 | nbview.insert_cell_below(edit) 211 | 212 | 213 | class InbComplete(sublime_plugin.EventListener): 214 | def on_query_completions(self, view, prefix, locations): 215 | nbview = manager.get_nb_view(view) 216 | if nbview: 217 | return nbview.handle_completions(view, prefix, locations) 218 | 219 | 220 | class InbMoveUpCommand(sublime_plugin.TextCommand): 221 | def run(self, edit): 222 | nbview = manager.get_nb_view(self.view) 223 | if not nbview or not nbview.move_up(): 224 | self.view.run_command("move", {"by": "lines", "forward": False}) 225 | 226 | 227 | class InbMoveDownCommand(sublime_plugin.TextCommand): 228 | def run(self, edit): 229 | nbview = manager.get_nb_view(self.view) 230 | if not nbview or not nbview.move_down(): 231 | self.view.run_command("move", {"by": "lines", "forward": True}) 232 | 233 | 234 | class InbMoveLeftCommand(sublime_plugin.TextCommand): 235 | def run(self, edit): 236 | nbview = manager.get_nb_view(self.view) 237 | if not nbview or not nbview.move_left(): 238 | self.view.run_command("move", {"by": "characters", "forward": False}) 239 | 240 | 241 | class InbMoveRightCommand(sublime_plugin.TextCommand): 242 | def run(self, edit): 243 | nbview = manager.get_nb_view(self.view) 244 | if not nbview or not nbview.move_right(): 245 | self.view.run_command("move", {"by": "characters", "forward": True}) 246 | 247 | 248 | class InbOpenAsIpynbCommand(sublime_plugin.WindowCommand): 249 | def run(self): 250 | view = self.window.active_view() 251 | nbview = manager.get_nb_view(view) 252 | if nbview: 253 | s = str(nbview.notebook) 254 | new_view = self.window.new_file() 255 | new_view.run_command('inb_insert_string', {'s': s}) 256 | new_view.set_name(nbview.name + ".ipynb") 257 | 258 | class InbInsertStringCommand(sublime_plugin.TextCommand): 259 | def run(self, edit, s): 260 | self.view.insert(edit, 0, s) 261 | 262 | 263 | class InbMoveToCell(sublime_plugin.TextCommand): 264 | def run(self, edit, up): 265 | nbview = manager.get_nb_view(self.view) 266 | if nbview: 267 | nbview.move_to_cell(up) 268 | 269 | 270 | class InbChangeCellTypeCommand(sublime_plugin.TextCommand): 271 | def run(self, edit, new_type): 272 | nbview = manager.get_nb_view(self.view) 273 | if nbview: 274 | nbview.change_current_cell_type(edit, new_type) 275 | 276 | class InbRenameNotebookCommand(sublime_plugin.TextCommand): 277 | def run(self, edit): 278 | nbview = manager.get_nb_view(self.view) 279 | if nbview: 280 | self.nbview = nbview 281 | sublime.active_window().show_input_panel("Notebook name", nbview.get_name(), 282 | self.on_done, None, None) 283 | 284 | def on_done(self, line): 285 | self.nbview.set_name(line) 286 | 287 | 288 | class RewritePromptNumberCommand(sublime_plugin.TextCommand): 289 | def run(self, edit, cell_index): 290 | nbview = manager.get_nb_view(self.view) 291 | if not nbview: 292 | raise Exception("Failed to get NBView") 293 | 294 | cell = nbview.get_cell_by_index(cell_index) 295 | if cell: 296 | cell.rewrite_prompt_number(edit) 297 | --------------------------------------------------------------------------------