├── .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 |
--------------------------------------------------------------------------------