Show More
@@ -0,0 +1,21 b'' | |||||
|
1 | """NotebookNode - adding attribute access to dicts""" | |||
|
2 | ||||
|
3 | from IPython.utils.ipstruct import Struct | |||
|
4 | ||||
|
5 | class NotebookNode(Struct): | |||
|
6 | """A dict-like node with attribute-access""" | |||
|
7 | pass | |||
|
8 | ||||
|
9 | def from_dict(d): | |||
|
10 | """Convert dict to dict-like NotebookNode | |||
|
11 | ||||
|
12 | Recursively converts any dict in the container to a NotebookNode | |||
|
13 | """ | |||
|
14 | if isinstance(d, dict): | |||
|
15 | return NotebookNode({k:from_dict(v) for k,v in d.items()}) | |||
|
16 | elif isinstance(d, (tuple, list)): | |||
|
17 | return [from_dict(i) for i in d] | |||
|
18 | else: | |||
|
19 | return d | |||
|
20 | ||||
|
21 |
@@ -0,0 +1,308 b'' | |||||
|
1 | { | |||
|
2 | "cells": [ | |||
|
3 | { | |||
|
4 | "cell_type": "markdown", | |||
|
5 | "metadata": {}, | |||
|
6 | "source": [ | |||
|
7 | "# nbconvert latex test" | |||
|
8 | ] | |||
|
9 | }, | |||
|
10 | { | |||
|
11 | "cell_type": "markdown", | |||
|
12 | "metadata": {}, | |||
|
13 | "source": [ | |||
|
14 | "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis." | |||
|
15 | ] | |||
|
16 | }, | |||
|
17 | { | |||
|
18 | "cell_type": "markdown", | |||
|
19 | "metadata": {}, | |||
|
20 | "source": [ | |||
|
21 | "## Printed Using Python" | |||
|
22 | ] | |||
|
23 | }, | |||
|
24 | { | |||
|
25 | "cell_type": "code", | |||
|
26 | "execution_count": 1, | |||
|
27 | "metadata": { | |||
|
28 | "collapsed": false | |||
|
29 | }, | |||
|
30 | "outputs": [ | |||
|
31 | { | |||
|
32 | "name": "stdout", | |||
|
33 | "output_type": "stream", | |||
|
34 | "text": [ | |||
|
35 | "hello\n" | |||
|
36 | ] | |||
|
37 | } | |||
|
38 | ], | |||
|
39 | "source": [ | |||
|
40 | "print(\"hello\")" | |||
|
41 | ] | |||
|
42 | }, | |||
|
43 | { | |||
|
44 | "cell_type": "markdown", | |||
|
45 | "metadata": {}, | |||
|
46 | "source": [ | |||
|
47 | "## Pyout" | |||
|
48 | ] | |||
|
49 | }, | |||
|
50 | { | |||
|
51 | "cell_type": "code", | |||
|
52 | "execution_count": 3, | |||
|
53 | "metadata": { | |||
|
54 | "collapsed": false | |||
|
55 | }, | |||
|
56 | "outputs": [ | |||
|
57 | { | |||
|
58 | "data": { | |||
|
59 | "text/html": [ | |||
|
60 | "\n", | |||
|
61 | "<script>\n", | |||
|
62 | "console.log(\"hello\");\n", | |||
|
63 | "</script>\n", | |||
|
64 | "<b>HTML</b>\n" | |||
|
65 | ], | |||
|
66 | "text/plain": [ | |||
|
67 | "<IPython.core.display.HTML at 0x1112757d0>" | |||
|
68 | ] | |||
|
69 | }, | |||
|
70 | "execution_count": 3, | |||
|
71 | "metadata": {}, | |||
|
72 | "output_type": "execute_result" | |||
|
73 | } | |||
|
74 | ], | |||
|
75 | "source": [ | |||
|
76 | "from IPython.display import HTML\n", | |||
|
77 | "HTML(\"\"\"\n", | |||
|
78 | "<script>\n", | |||
|
79 | "console.log(\"hello\");\n", | |||
|
80 | "</script>\n", | |||
|
81 | "<b>HTML</b>\n", | |||
|
82 | "\"\"\")" | |||
|
83 | ] | |||
|
84 | }, | |||
|
85 | { | |||
|
86 | "cell_type": "code", | |||
|
87 | "execution_count": 7, | |||
|
88 | "metadata": { | |||
|
89 | "collapsed": false | |||
|
90 | }, | |||
|
91 | "outputs": [ | |||
|
92 | { | |||
|
93 | "data": { | |||
|
94 | "application/javascript": [ | |||
|
95 | "console.log(\"hi\");" | |||
|
96 | ], | |||
|
97 | "text/plain": [ | |||
|
98 | "<IPython.core.display.Javascript at 0x1112b4b50>" | |||
|
99 | ] | |||
|
100 | }, | |||
|
101 | "metadata": {}, | |||
|
102 | "output_type": "display_data" | |||
|
103 | } | |||
|
104 | ], | |||
|
105 | "source": [ | |||
|
106 | "%%javascript\n", | |||
|
107 | "console.log(\"hi\");" | |||
|
108 | ] | |||
|
109 | }, | |||
|
110 | { | |||
|
111 | "cell_type": "markdown", | |||
|
112 | "metadata": {}, | |||
|
113 | "source": [ | |||
|
114 | "### Image" | |||
|
115 | ] | |||
|
116 | }, | |||
|
117 | { | |||
|
118 | "cell_type": "code", | |||
|
119 | "execution_count": 6, | |||
|
120 | "metadata": { | |||
|
121 | "collapsed": false | |||
|
122 | }, | |||
|
123 | "outputs": [ | |||
|
124 | { | |||
|
125 | "data": { | |||
|
126 | "image/png": [ | |||
|
127 | "iVBORw0KGgoAAAANSUhEUgAAAggAAABDCAYAAAD5/P3lAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\n", | |||
|
128 | "AAAH3AAAB9wBYvxo6AAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURB\n", | |||
|
129 | "VHic7Z15uBxF1bjfugkJhCWBsCSAJGACNg4QCI3RT1lEAVE+UEBNOmwCDcjHT1wQgU+WD3dFxA1o\n", | |||
|
130 | "CAikAZFFVlnCjizpsCUjHQjBIAkQlpCFJGS79fvjdGf69vTsc2fuza33eeaZmeqq6jM9vZw6dc4p\n", | |||
|
131 | "BUwC+tE+fqW1fqmRDpRSHjCggS40sBxYDCxKvL8KzNBaL21EPoPB0DPIWVY/4NlE0ffzYfhgu+Qx\n", | |||
|
132 | "GHoy/YFjaK+CcB3QkIIAHAWs3wRZsuhUSs0CXgQeBm7UWi/spn0Z+jA5yxpEfYruqnwYllRic5a1\n", | |||
|
133 | "MaWv8U5gaT4M19Sx396IAnZLfB/SLkEMhp5O/3YL0AvoAHaKXl8HLlZK3QZcpbWe0lbJDOsaHuDU\n", | |||
|
134 | "0e4u4JAy2wPk/C1JzrKWArOQ0fUtwH35MOysQxaDwbCO0NFuAXoh6wPjgQeUUvcqpUa0WyCDoQls\n", | |||
|
135 | "CIwBjgfuAV7KWdY+7RWpmJxlXZezrEdylvXxdstiMKzrGAtCYxwI/EspdZbW+g/tFsbQ67kQuBHY\n", | |||
|
136 | "FNgseh9FV6vCbUAeWBC9PgBeq2EfS6J2MQOBrRDTe5KdgAdzlvW1fBjeUUP/3UbOsoYBE6OvG7VT\n", | |||
|
137 | "FoOhL9Af+BUwFLkZpV+DaY6V4UPkRpb1+ncT+m8nGwK/V0oN01qf025hDL2XfBi+DLycLMtZVo6u\n", | |||
|
138 | "CsKfGnSq8/NheEpqHwOBEcDBwJnAsGhTP2ByzrJG5cPwnQb22Sy+0G4BDIa+RH+t9dmlNiqlFKIk\n", | |||
|
139 | "JJWGi+jq5JPmq8BbJJQArfXqpkncczlbKbVQa/3rdgtiMNRCPgxXAK8Ar+Qs63LgXmDvaPPGwPeA\n", | |||
|
140 | "H7VJvCRfbLcABkNfouwUg9ZaAwuj178BlFLvVejzgR4WFviM1npcuQpKqf6IyXIjxLS7GzAWuUnu\n", | |||
|
141 | "XsO+fqWUellr3ZBJdq/jr9+BDn1uve07O9Rz0y6f8PtGZGgWe53oT6SBkZ/q1/nHZy47aloTRTKU\n", | |||
|
142 | "IR+Gy3OWNR6Zxtg0Kv4KRkEwGPocxgcBiCwcsSI0F5iOhF+ilPok8C3gVGS+thK/VErdrbWuO2ys\n", | |||
|
143 | "s/+aLZTuOKbe9krrIUCPUBB0B+PQ1P1bdKe6EzAKQgvJh+GbOct6gkJkxM45y+qXDIWMHBhjBWJe\n", | |||
|
144 | "PgyDWvaRs6zPIVObAG/nw/DpEvUGAp8E9gGGJzbtl7Os7cvs4skqp0V0Yl8jgcOBjyMDhbmIZeWl\n", | |||
|
145 | "fBg+UUVfReQsayhwELAnsAXi6/E28BxwTz4MP6iyn92RaSCA+/NhuCwqXx9R4MYhU0MfRTK/AjyW\n", | |||
|
146 | "D8MFGd0ZDFVhFIQKaK3/BXxfKXUlklTq0xWafAI4Driyu2UzGLqRlygoCArYHJif2H4gcFb0+Z2c\n", | |||
|
147 | "ZW2bD8NV1XScs6yNgH8g/jsAPwCeTmzfFPgjYsnbiez71MUVdnMQcF8V4nyUs6whwB8QX4+0s2Ys\n", | |||
|
148 | "0yPAt/NhGFbRZ/wbzgO+DaxXotqqnGX9GbigCkXhf5CBCsDngYdzljURGQhsWqLN+znL+iFwdT4M\n", | |||
|
149 | "dYk6BkNJTJhjlWitQ2Bf4P4qqv848t8wGHor6Yd9+ruHJFkC2BI4rIa+D6egHKwmstYlGAxMQCwH\n", | |||
|
150 | "rRjEPI5ER5S7ZvcFXsxZ1phKneUsawSi8HyH0soB0bbvAM9Ebaplt5xlnYkct1LKAYiFZhJwSQ19\n", | |||
|
151 | "GwxrMRaEGtBar1RKfRX4JxIzXortou3PN1mE+YgJsSwaeoLHOQCqUy3QSr9eqZ6G/gq2aYVMhqrY\n", | |||
|
152 | "OfF5FeJwvJZ8GM7JWdY/gC9HRS7wtyr7Pjrx+e6MqYC3KLbU7Qhck/h+FJIKvRRVjfSREXicU8EH\n", | |||
|
153 | "pgAvIIqLBZwGfC7avl5Uf29KkLOsTZCMq8npj9sQx89no37HIlaAODplNPBIzrJ2z4dhNVlaT0HC\n", | |||
|
154 | "XwFmIkrAC4if2PaIz8/3KCgn385Z1pX5MJxeRd8Gw1qMglAjWutlSqnTgUcqVP0SzVYQtP5mcMXE\n", | |||
|
155 | "SvvtUUy9YsK5QEWHy7EnTB6lOtSsFohkqEDOsgYAdqJoagkT9Z8pKAj75yzr4/kwnF2h748ho/GY\n", | |||
|
156 | "q9J1oqiKLj4JOctKK8Yz8mH4Yrl9VcnHkXVYTsyHoZ8WJWdZNyPThbF5/3M5yzowH4alpi9+T0E5\n", | |||
|
157 | "WA18Nx+Gf0zVeRG4KmdZ90R9bwCMRKwyX69C5h2j91uA4/JhuCSxbTYwJWdZtwNPIFbifsAFSISZ\n", | |||
|
158 | "wVA1ZoqhDrTWjyIjjXIc3ApZDIZu4ELgY4nvt5Wody8wJ/qsgBOr6HsihfvOfCRrY7v5dYZyAECk\n", | |||
|
159 | "GP0ISEZmZYZ55yxrB8SyEXNxhnKQ7Pt64H8TRUfmLGuXKmWeC4xPKQfJvp9CLCJlZTYYymEUhPq5\n", | |||
|
160 | "tcL2XVsihcHQJHKWtU3Osi5GnAZj5iKWgiKitRouTxQdl7OscnPu0HV64dp8GLY7R8pyxEGxJPkw\n", | |||
|
161 | "fBcZ9ceUSvN8IoV76upK/UZcgawcG3NKqYopfleFU+gDic/b5SzLWIwNNWFOmPqp5CG9sVJqPa11\n", | |||
|
162 | "VZ7dBkOL2D1nWcmcBkOR8MFtgM/QdTXJZcCR+TBcXqa/SYj5egAFZ8VMX4ScZe2FRPnEXF2z9M3n\n", | |||
|
163 | "3nwYVsrtAmK6/0z0uVR4ZXLtivvzYfhGpU7zYbgkZ1k3ACdHRQdWIQsUO3ZmkUzB3Q/xjaolLbeh\n", | |||
|
164 | "j2MUhDrRWr+mlFpJ+eV5hyIxz4YWs98Fj/Rf8uZbozo0/ZYt7D8rf9ORK9stUw/hU9GrEnMAp1R+\n", | |||
|
165 | "gph8GL4bzdNPiIpOorSzYtJ68FS1IYPdTLWp3hcnPm+Q3pizrA7E+TCmFn+aZN0dcpY1LB+G5e4b\n", | |||
|
166 | "y6rM8bA49X39GmQyGMwUQ4NUGnkMrbDd0A3sdeLk4z6cN+89pTtDTWd+gyErF+7pTv5eu+XqJbyK\n", | |||
|
167 | "TDHsmg/DJ6tsc2ni8+dzljUqXSGaevhmoqjIObFNVBzlV8kQug4W5tbQNl13WGatAv+poW+DoW6M\n", | |||
|
168 | "BaExPgC2LrO9nHWhpSilDqI4NPMhrfXUJvS9M/DfqeJXtdY3N9p3rex50uQ9lFKT6BrTvoFCXbTX\n", | |||
|
169 | "yZNfmnrZxHtbLVMP4xng74nvK5DzeD7wfIWRayb5MHwiZ1kzgF0oOCuemar2ZQoK8zLgr7Xup5t4\n", | |||
|
170 | "s0n9DEl9b0RBSPeV5q0a+jYY6sYoCI1RacnZ91siRXUMAH6eKnsYicdulDOAY1NlpzWh35pRqG9R\n", | |||
|
171 | "IuGN7uw4AfG878s8nw/DX3RDv5dScGY8NmdZP86HYXJaJzm9cHMp7/s2UHdK9BTpKaxBNbRN163k\n", | |||
|
172 | "t9Rux05DH8FMMTTGZhW2v9sSKarjbopNk/sqpUY30qlSahCSGS/JCuD6RvqtF6UpMm/HaHTJbYaG\n", | |||
|
173 | "mQzED/0umRVzlrUZhXwJ0HOmF5pJOlXyxzJrZbNt6rtZP8HQIzAKQp0opTZAlsItxTKtdTnv75YS\n", | |||
|
174 | "LR7lpYqrjV0vx2EUH4fbtdZtucnpMqOrDjPy6jYii8DkRFHSYnAEhem22cBjrZKrVeTDcCldTf/p\n", | |||
|
175 | "h345ksrEGprnF2EwNIRREOrnMxW2z2uJFLVxJcXmy2OVUo34ShydUda+EaIq7T2u0SZTY/eSdFY8\n", | |||
|
176 | "MGdZm0efk86J6/LCQUnFp5pIkZjkcvQz8mH4YZPkMRgawigI9VNp7v7BlkhRA1rr+RQneNqC2hba\n", | |||
|
177 | "WYtSajiS9z3JXLomaGktq/VllLIUdKqSWe0MjZMPwxlIel8Q/6Zv5CxrGIX8AJ10XU+hFtIRQ+UW\n", | |||
|
178 | "KWoXyYyTu+Qsa79KDXKWNRpJyx5zZ9OlMhjqxCgIdaCU6g98o0K1npBCNotLM8rcOvuagCRgSXKN\n", | |||
|
179 | "1rozq3IrCCZNfFkrfRjotWsCaJinUBODK51/tkuuPkTy/DoYOIDCfeb+fBjW4t2/lqhdcmRdbUri\n", | |||
|
180 | "VnILXS2HZ1WRvfAcCk61K4A/dYdgBkM9GAWhPr5F6XSrIBf6Qy2SpSaidSReShV/XilV7veUIj29\n", | |||
|
181 | "oOkB2fGmXT7x7sCbOGpFf7VZx4A1m0/znG2nehMyc+0bms7NFJxzxwH7J7Y1OvWUPG9/mLOsLRvs\n", | |||
|
182 | "r6lEaaOT0TtfBB5ITLWsJWdZg3KWdRNwTKL4wnwYzu9mMQ2GqjFhjjWilBqBpJYtx51a66UV6rST\n", | |||
|
183 | "S+maJz52VvxRdvVilFK7UbzexGNa67Kr+bWS6X+ekPYs79HkLGt34JOI+Xyz6D2d1vfMnGUdini6\n", | |||
|
184 | "L0C851/Oh2HD+SyaQT4MV+YsaxJyLm1Gwf9gAXBHg93/JNHHtsArOcuajCztPBDYCkkytBXg5sOw\n", | |||
|
185 | "5QmF8mF4W86yLgK+HxXtC8zKWVaALMm8CslHsicS7RFzL8VhyAZDWzEKQg0opbYE7qd8prPVdF2h\n", | |||
|
186 | "rSdyLfALYMNE2XFKqR/XsHbEURll62L4Wiv5PuBUqPPF6JXkLuCQbpGoPi4HfohYKGMHWD9axrlu\n", | |||
|
187 | "8mF4Z7RuwfioaDBwaonqRemQW0U+DH+Qs6xFwHnIFNwQsv+3mMnA8dHiVwZDj8FMMVSJUuow4DkK\n", | |||
|
188 | "a7GX4gqt9cstEKlutNaL6boULMho5tBq2iul+lH8IFuCmJcNfZx8GM6hOCFVU5THfBhOQHxfylkH\n", | |||
|
189 | "3gY+asb+6iUfhhcCewC3l5BlFbJk/P75MDwqlVTKYOgRKK1rizhSSk2h67ximo1abV5XSi2n9EIk\n", | |||
|
190 | "z2itx5XYVqnfQcjI7DiqW2XtfeCTUbRA3ex50nWfUrqjeJEcrfcLrpj4SCN9xyilxgDPp4of0Fof\n", | |||
|
191 | "UEXbg4B/pIqv1FrXnVNh7AmTR3V0qIwwRH1E4E28pd5+De0hZ1m/Bb4bfX0+H4Z7dMM+hgGjkDwC\n", | |||
|
192 | "S5FpjFk9bR4/Z1mDkGmF4VHR20g4Y3oxJYOhR9EXphg6lFLlVjFbH0mZvDGwCTAayCFe0ntTOZ1y\n", | |||
|
193 | "zDLgkEaVg1ahtX5BKfUU8OlE8ReUUjtorSstCduzch8YehSR5/6ERFG3nBvRuhE9frXUfBguA6pd\n", | |||
|
194 | "+Mpg6DH0BQXBBro7o+Ea4Bta66e6eT/N5lK6KggKOAE4u1QDpdTGFOdNmNkLf7uh+zgYcRQEMa+3\n", | |||
|
195 | "Je22wWBoDOOD0DhLgYla67vaLUgd3ETxglLHRXkeSnEExQ5gbQ9tNPQokis5TsqHoVlbwGDohRgF\n", | |||
|
196 | "oTECYHet9Y3tFqQetNYrKDb/DqN46eYk6emF1UhUhMFAzrImUEhDvgr4VRvFMRgMDWAUhPpYAvwf\n", | |||
|
197 | "8Bmte31+/8uQBEdJMjMrKqW2o5A2N+YfWusePw9s6F5yltWRs6zxwKRE8RXtyEVgMBiaQ1/wQWgm\n", | |||
|
198 | "eWTe/jqtdU9Zz74htNavKaXuAw5KFB+glBqptZ6Tqj6RQlrYGDO90AfJWdY5wNeQFQwHIAmetk5U\n", | |||
|
199 | "eZFCsiCDwdALMQpCed5AphEC4NF12BHvUroqCAoJ7TwvVS+d++BdJEmPoe+xKRLnn0UeODwfhm3N\n", | |||
|
200 | "RWAwGBqjLygIbwN/LbNdI1MGH6ReL/eWkMUmcDeSeGa7RNlRSqnzdZQoQym1C7Bzqt11NWReNKxb\n", | |||
|
201 | "zEMU6GHAesBiYCaSLOviaF0Cg8HQi+kLCsLrWuvT2y1ET0ZrvUYp5SG57mO2Bz4LPB59/2ZRQ5P7\n", | |||
|
202 | "oM+SD8OLgYvbLYfBYOg+jJOiIeZKxOs8STJiIb28daC1/lf3imQwGAyGdmEUBAMA0XTKraniI5VS\n", | |||
|
203 | "A6O0zOnloI31wGAwGNZhjIJgSHJp6vtgJBNlehW65cANLZHIYDAYDG3BKAiGtWitHwVeShV/muLF\n", | |||
|
204 | "uW7VWi9qjVQGg8FgaAd9wUnRUBuXAn9IfN8f+FyqTo/OfbDnSX8brDpXnqEUe2ropzQvdtDx66ev\n", | |||
|
205 | "GN9XolIMPQDb9T8LrBd4zsPtlsXQe7Bd/0BgQeA5QbtlMQqCIc21wC+ADaPv6WWu5wAPtVKgWtjt\n", | |||
|
206 | "6Os2XG/9jhdQjIzTQ2rFF9bQecy4E2/I9UQlwXb9LYDDK1R7K/Cc21shj6FxbNcfDjwGKNv1Rwae\n", | |||
|
207 | "83q7ZWo2tusPBb6ELGW9BbAICX99Gngs8Jx0hlZDBWzXHwvcC6ywXX9o4DlL2ymPURAMXdBaL1ZK\n", | |||
|
208 | "+ZRItwz8Jc6N0BMZMFB9GxiZsWnzTjrPAH7QWomqYgTF/h9pngC6RUGwXf+XwC2B50ztjv57M7br\n", | |||
|
209 | "XwJMCjxneo1NP0SWgAfJq7LOYLv+esAFwOkUL9wWM912/d0Dz+lsnWQ9A9v1BwEXAT8PPKfWVOML\n", | |||
|
210 | "kPVt3kNWQm0rxgfBkEWph5UG/tJCOWqnQ40ttUkrvWcrRamWwHOmAZsguSfGAi9Hmy5AUhgPAz7f\n", | |||
|
211 | "Hfu2XX8k8ENgx+7ovzdju/4uwP9D/peaCDxnCbANsF3gOYubLVu7sF1/AHAHcBaiHDwI/C+ywNsE\n", | |||
|
212 | "4KfA68BdfVE5iNgbOBmxqtRE4Dn/BoYDnwg8Z02zBasVY0EwFKG1fkEp9RTioJjkIa11zzaVarYq\n", | |||
|
213 | "vVFt2TpBaiN6oCwB5tiu/2FUPCvwnLTTaLM5oJv77800dGwCz1kXHXkvRNKydwI/Cjzn1+kKtuuf\n", | |||
|
214 | "i2TX7Ks0et681yxBGsUoCIZSBBQrCL0h98EbdW7rddiuPwoYFJu/bdffFNgL2BZ4DZgWKR5ZbRWS\n", | |||
|
215 | "2+KIqGiE7fpjUtXmlrtZRdaHscBAYDowM/CckimWbdffFfgw8JzXou/9kfUccojV5MXAcz4s0XYw\n", | |||
|
216 | "sCsymu8PzAVmBJ7zVqn9pdoPRVKF7wSsAN4EgqzRve36HcAoZDEqgO0zjs3rged8kGo3gOJ05ADT\n", | |||
|
217 | "s0bTkan+k9HXGaVGjNFxykVf81nH2Hb9Ich/MRJJeT291H9fL7brj6CwANfPspQDgOi3rijRx/rI\n", | |||
|
218 | "b8kB7wPPBZ4zL6Ne/JvfCDzn/WhufhvgvsBzVkR1dgN2AR4JPGduom38P7wXeM7c6FzfCfgU4iMR\n", | |||
|
219 | "lFLebNfPIefXzMBzikz8tusPQyx676bljmTeCfhyVLST7frp//TV9Dluu/6GwOhUvTWB58zIkjFq\n", | |||
|
220 | "sykyNfmfwHMW2K7fLzoWeyDTFPnAc14t1T7qYwNgT+Rc/wi5ZyT/N20UBEMRSqn+wNdTxQspTqTU\n", | |||
|
221 | "41BaP6yVOipzGzzSYnG6m6uBz0YPv7OQm3dytc35tuuflHZutF3/BuArwEaJ4p/QNdU2wGnAH9M7\n", | |||
|
222 | "jRSTG5CbS5LQdv2joymTLKYBzwHjbNc/DomW2TCxfbXt+sMCz3k/sa8RwM+Qh/X6qf5W2q4/CTit\n", | |||
|
223 | "zMN1OPB7CopQktW2658YeM5fEvXvRKZzBiXqZaWUPha4JlW2NfB8Rt0hiANfmjWIuf5jiLPfvVm/\n", | |||
|
224 | "AfmvbgNmB54zKrkheuD+Bjg11Wap7fpnBJ5TybelFk4E+iE+Fb+ptbHt+scg//nGqfJbgeMDz1mY\n", | |||
|
225 | "KN4UOZYX2q7fSWHhuNdt198ZOBc4MypbbLv+5wPPeTb6PiJqe5ft+ichx3WXRN8rbdc/OfCcrGis\n", | |||
|
226 | "R4ChiHKSlSn2f4BzkOvitMRvCKJ9DEzU9TPafwGZlkkyBvExSrKUrtdnmoOBycA5tus/iCyat3li\n", | |||
|
227 | "u7Zd/0rk2ihS1mzXPwT4E3LulaLTKAiGLL6EaMlJbtBat91pphIjFw289t9DVh4N7Jva9EKnWnpJ\n", | |||
|
228 | "G0RqBXcjCa08YCqy/PJE4L8A33b9HQPPeTNR/0bgvujzGchoywPSq5U+nd6R7fp7IDfRjYDrEE99\n", | |||
|
229 | "DeyHrPb5lO364xI36zTb2q4/AUnt/SSyLHQHMvJZklQOIhYChyCLid2FWBoGIQrDfwGnAP8Gskzd\n", | |||
|
230 | "VvSbBgPvIMdpJjLHuxdikXgg1ewa4Jbo84+BHRAFI/3gT9/QQZa+/iIy9zwccVQrSeA5nbbrX4s8\n", | |||
|
231 | "cI6htIIQK7xdFJLIAvEEYjmYBlyP/E4LeXj92Xb94YHnnFtOjhrYJ3q/vtbpE9v1fwqcjYxUL0GO\n", | |||
|
232 | "51bI//g1YIzt+mNTSgJIivfNEIXgBOThfx0ySv8Nct7vgzgfj0+1HQf8E5iPKM/vI+vLHA9cZbs+\n", | |||
|
233 | "JZSEevgDBZ++3yIKzgVI1FeSrCnD6ci0zebAJxCfjmoZjxzXPPBL5By0gW8jCt3sqHwtkYL1N0RB\n", | |||
|
234 | "/R2ymOG2yHE5CLFAHAu8ahQEQxbfyijrDdML3HTTkWvUBRfsb88bPb6TzjEK+oHKL184YHL+Jmdl\n", | |||
|
235 | "u+XrJsYBhwaec0dcYLu+hzw0dkcu/AvjbUmLgu36DqIgPB54zuQq9nURMgI8LjnyBibZrj8z2s/l\n", | |||
|
236 | "tuvvVcJJbWvkXDoi8JzbKu0s8JxFtut/IqXgAPzOdv0/IiPnb5KhICAjpMGIEjAhPV1iu35HWsbA\n", | |||
|
237 | "c25ObD8ZURAeqibENBqpTYnark8FBSHiakRBOMx2/cHpB29kSv4KooSlLRYnIcrBHcBXk7/Fdv0b\n", | |||
|
238 | "gReAM23Xvz7wnJlVyFIJK3qfXUsj2/U/jiiiq4B9ktEytuv/Fhlpfx2xEnw31XxHYLfAc6bbrv8k\n", | |||
|
239 | "cny/Bnwz8Jy/2q6/DTLd9F8Zu94ceXAeEHhOvM7MNbbrT0UU4vNs15+c2FY3gedcm/hNP0EUhDvL\n", | |||
|
240 | "KMrJtkuIFPboWNWiIOSAO4HDE7/Dj67FSxEn21+m2pyOWDpuCDxn7fG2Xf8e4F1EIVsceE5oohgM\n", | |||
|
241 | "XVBKjURuSEke11qXMhv3OPR553VO9Sb407yJZwTexO8FnnNV/qYj11XlAOCfSeUA1s4D/y36mp7f\n", | |||
|
242 | "rAvb9fdGLDMzU8pBzMXIg2wsMhLKQiFhgxWVg5gM5SDm+uh9VHqD7fr7IlaNFcAJWb4UPcHLPvCc\n", | |||
|
243 | "2YgVZn3gyIwq30AsQg8lQ+aiefUfR1/PzlB08sD9Udusfmsi2t+Q6GutjspnIE6L16dDaSN/irMR\n", | |||
|
244 | "p8dTbddPOxK/nwgxTZr8747e30SsEkNL7PvXGQrAVYgvwggK/gK9mXMyfuON0fvWkY9Dkp2i97uT\n", | |||
|
245 | "hYHnLKNgURsDxknRUMz5FJ8XP22DHIbqSc9pxsSOW8ObtJ89ovdXbNcvpQC8j4zcdiTbnAoy4q2b\n", | |||
|
246 | "6Ia3CYV5/Y0zqsXOf4/WEYveaq5GQuOOQaZekhydqJNkW2BLZF2UzhL/R+xE2XAIa+A52nb9lUho\n", | |||
|
247 | "Y63hd7GD5d1ZGwPPmW27/iuIUrkLXc/n9xP13rZd/yNgVezoF8n1NjAyyyKETGGl97fGdv1/IlaL\n", | |||
|
248 | "3h7e+06WM2PgOQtt11+GTMcNo6vVJ1aWsyK+4nvFQjAKgiGBUmoshfnOmGe11vdl1Tf0GOaUKI9v\n", | |||
|
249 | "lqrE9lqJb6b/Hb3KsU2Zba/VslPb9bdDfA0ORLz0N62iWWxVqMkc3iZuRuawP2u7/g6JKI9RSCTR\n", | |||
|
250 | "YoodhOP/YgNKK2Ix2zZJzjnINMN2NbaL/4uiaIUE/0EUhB3pqiCkMwl2IscjXZZFJ/B2iW1xRtWR\n", | |||
|
251 | "ZWTqDcwps63U9f8Q0TSN7fp/iK0PtuvviPjmrCHyR1qrICilNkTmHjZDLsDke/JzOtwnzY1KqXcR\n", | |||
|
252 | "R4cFiBab9XlRT87I19dQSo1GNPz0tJOxHvR8mhrOVobB0XuAOBiWo1zmwaqdXW3X3x+4BzGVv4SM\n", | |||
|
253 | "pN9AnPEg21McxMIArTs2dRN4zoe26/8NOA6xGJwfbYqV9b8GnrM81Sz+Lz5A0qOXo2y4Ww3MoT4F\n", | |||
|
254 | "IY4+KTfNF58TaXN4VthstVNDitLKcdxvOjKmEj0tv0M953fs87E3Eul0B2JliBflOzfwnFcA+iul\n", | |||
|
255 | "5iEmwQFNEBaK569L0amUWggcqrXO8gg2FKHG2CdW4Uem9XvBlUflu7RUaiByU3lPa92ZKN8cSav8\n", | |||
|
256 | "fUQBTHKr1rrqueIsxp18/eg1azrLjSYB6NfRsY3G6Is9nDjDYxh4zundvbMotvtm5N50duA5P09t\n", | |||
|
257 | "T0faJIkfirU+zNrF1YiC4FBQECZE73/JqB//F+u14r+ImIVEOB1iu/6ZNfhwzEamp7YuU2e7RN1m\n", | |||
|
258 | "oZBnW5YVIfZ1qNWfotw51yuIph++hET0bAkcikwpTAEuCjxnSly3PzIP0a8NcnYgD6SBlSoaIhQX\n", | |||
|
259 | "V2UtVup24LBU6S7IyG+NUuodZP52awojrTSvIjeshlij9XdQKh2jXYRRDtpGfOCruQfEpmzbdn0V\n", | |||
|
260 | "dP9iPLsgjnEryI67Lzd/PCt6/5Tt+v3LJXAqQ/z7ut2ZO/Ccx23XfxUYZbt+7D8xCngl8Jwsa80s\n", | |||
|
261 | "ZBS8ke36O7cg4ybA5UgegJ0QE/XN5auvZRaiIMQRF12wXX8TCv9ls6eERpOtIMR+EXNS5YsRh8dS\n", | |||
|
262 | "To/V+CzUck21i6uR5++4wHNeKFXJRDH0PfoR5fqmtHKwDDhCa73O5JA3lCSeF04v6Z3FPRTMzBO7\n", | |||
|
263 | "S6AE8Q12PbomgYn5Xpm29yMPhu2RUK96iKMn9q6zfa38JXo/NHoly7oQeM5K4Iro60+jKINuJVJC\n", | |||
|
264 | "Yu/439uuX805A4VkWyfbrp+V/MdFnOmeCmpfFKsSRYMc2/U/DeyG3OfSjpOx5WmfVHmcuXFcFfus\n", | |||
|
265 | "5ZpqObbrb45EtswqpxyAcVI0FDMbOFxrXeT9a+heopvnEArzolvashT0wmbEapdgGpIU5XDb9R9F\n", | |||
|
266 | "YqrXQyyL8wPPeTeuGHjOMtv1T0VuqldH6W//jigNmyHOcAcBgwPPcZog20xkRLcJ8DPb9S9CRqM7\n", | |||
|
267 | "I7kDvoDE1hfdxwLPWWy7/plI7oCLbNffHXm4zUQeRtsjGRP/EXhOKSfcABkpj49i5+9G/putgHmB\n", | |||
|
268 | "5yxIN4iSF21C14V6Rtiu/yYSW15uHv4a4P8oKAedlPcvOAv4KmItfCTKKfAS8v8NR1ILHwnsl5GA\n", | |||
|
269 | "qF7ORdYaGA48HGWyfBqYgViDRwCfQR72PkDgOU9E2TvHI4m0TgeeRczb30DyH2iKcyA0ymrgWNv1\n", | |||
|
270 | "FyDK1NvIQ3tStN3LCH+9HUl29UPb9echFo8BUbtLEKfJtJ9EmgA59ifbrj8bCR3cGDlvZqdTLcPa\n", | |||
|
271 | "9NCbUMhs2GFLKvPFSAKxZl7/CxEL8pgoA+QMxD+kE3HenAHcHnjOGmNB6Dt8iGjHWSFKK4HHkcQr\n", | |||
|
272 | "OxvloLXYrr+77fqrEIejNyiE6P0WccZbabv+lFLtG+Ry5AY/BHkYfRDtR9M79QAAA3FJREFUcwYS\n", | |||
|
273 | "NdCFwHPuQR6a7wHfAR5GMhk+i9xcT6G6KIOKBJ6zFBn9r0GUmBlIWN9ziHf/5yjO/phsfy2yqt4i\n", | |||
|
274 | "xOJxF3INTI9k/Q7ZoV4xv0PC5LZCci4sQm6g08kYHdquvxy5lt4DwsSmF5EENCts1//Idv3M9LbR\n", | |||
|
275 | "egJTkEx4NvBA1joFifqLIjkeR6wcfwdeQfIFTEEcjHNU79RXkShvw95Ixs5+yOj/KuSh+ATiAHcq\n", | |||
|
276 | "xb4fxwOXRfJMQc6zlxGF6B3g4MBznmmWnBFzEUfP0xDFcCGiAG+JHKushESXIdanjRBF4l3EInAj\n", | |||
|
277 | "8vuOqWK/5yNRGaOQFNkfIhkOX6CQgwAA2/W3jkI3V0T7ejjatAFyXb2PXP/LbVnroWGi6bbzo697\n", | |||
|
278 | "IlaWk5Br93wkk+jztusP7o94Lna7eaoMZU0cVXIAped7eqGZfP2ZqmPFl+ptrVf3n19UpvVMYLRS\n", | |||
|
279 | "agBywxuEjLwWAe9qrTMXV2mUzs7OP/Xrp+6qt33Hmn5Zue3XNeZTOVoky5nqKiQkrNT883Qk3WvJ\n", | |||
|
280 | "sMLAc1bbrv9Z5AH6KWRkOB+5wRWlWo7a3Ga7/mOIomAho/GFyI30YeDREru7ELlOq07TG3jONbbr\n", | |||
|
281 | "T0Nu9KOQm+i/gFsDz3nTdv2fI2FbpdpfHnlpH4LcnHdAlIz5yLErqXgFnvOR7fo28lDYE7lu3kKO\n", | |||
|
282 | "TdZ9K52xrhTl7knnUVB6SqVeTsr4apQU6lDEbG4hCsFbROsRBE1ebjrwnNB2/XGIGf5gRBkYhPyv\n", | |||
|
283 | "7yDpjR9MtVkOnGK7/vWIgrFrVPcF4O8ZKbaXIuduWkH6KfL/JbkEsWClfWK2CDzHt10/jzhXjkGO\n", | |||
|
284 | "yzNIZEiRD00ga3ocaLv+kUh2xo8hSuVURKmIUyiXVGYCWVzKQlJD7xrJNg85b9LX8RLgF6X6SpFU\n", | |||
|
285 | "9Cpe28gaJgORqEEAbNffDLlvHIQoAndR8NEYilwjExD/nwuUiTQ0GAwGw7qC7fqjEUvKqsBzmhWd\n", | |||
|
286 | "t05gu/5pyNoifw48J9N5PForxQeeNFMMBoPBYDD0DWL/llvK1In9jt4zCoLBYDAYDH2DePo5MwrJ\n", | |||
|
287 | "dv0hFPwTnjBRDAaDwWAw9A3+hPgOHRPl25iK+FhsiuR4OARx0Lwf+J1REAwGg8Fg6AMEnvNklL78\n", | |||
|
288 | "HMRRca/E5hVINNIVwI2B56z6/3ExLRI31pXNAAAAAElFTkSuQmCC\n" | |||
|
289 | ], | |||
|
290 | "text/plain": [ | |||
|
291 | "<IPython.core.display.Image at 0x111275490>" | |||
|
292 | ] | |||
|
293 | }, | |||
|
294 | "execution_count": 6, | |||
|
295 | "metadata": {}, | |||
|
296 | "output_type": "execute_result" | |||
|
297 | } | |||
|
298 | ], | |||
|
299 | "source": [ | |||
|
300 | "from IPython.display import Image\n", | |||
|
301 | "Image(\"http://ipython.org/_static/IPy_header.png\")" | |||
|
302 | ] | |||
|
303 | } | |||
|
304 | ], | |||
|
305 | "metadata": {}, | |||
|
306 | "nbformat": 4, | |||
|
307 | "nbformat_minor": 0 | |||
|
308 | } No newline at end of file |
@@ -0,0 +1,19 b'' | |||||
|
1 | """The main API for the v4 notebook format.""" | |||
|
2 | ||||
|
3 | # Copyright (c) IPython Development Team. | |||
|
4 | # Distributed under the terms of the Modified BSD License. | |||
|
5 | ||||
|
6 | from .nbbase import ( | |||
|
7 | nbformat, nbformat_minor, nbformat_schema, | |||
|
8 | new_code_cell, new_markdown_cell, new_notebook, | |||
|
9 | new_output, output_from_msg, | |||
|
10 | ) | |||
|
11 | ||||
|
12 | from .nbjson import reads, writes, to_notebook | |||
|
13 | reads_json = reads | |||
|
14 | writes_json = writes | |||
|
15 | to_notebook_json = to_notebook | |||
|
16 | ||||
|
17 | from .convert import downgrade, upgrade | |||
|
18 | ||||
|
19 |
@@ -0,0 +1,249 b'' | |||||
|
1 | """Code for converting notebooks to and from v3.""" | |||
|
2 | ||||
|
3 | # Copyright (c) IPython Development Team. | |||
|
4 | # Distributed under the terms of the Modified BSD License. | |||
|
5 | ||||
|
6 | import json | |||
|
7 | import re | |||
|
8 | ||||
|
9 | from .nbbase import ( | |||
|
10 | nbformat, nbformat_minor, | |||
|
11 | NotebookNode, | |||
|
12 | ) | |||
|
13 | ||||
|
14 | from IPython.nbformat import v3 | |||
|
15 | from IPython.utils.log import get_logger | |||
|
16 | ||||
|
17 | def _warn_if_invalid(nb, version): | |||
|
18 | """Log validation errors, if there are any.""" | |||
|
19 | from IPython.nbformat import validate, ValidationError | |||
|
20 | try: | |||
|
21 | validate(nb, version=version) | |||
|
22 | except ValidationError as e: | |||
|
23 | get_logger().error("Notebook JSON is not valid v%i: %s", version, e) | |||
|
24 | ||||
|
25 | def upgrade(nb, from_version=3, from_minor=0): | |||
|
26 | """Convert a notebook to v4. | |||
|
27 | ||||
|
28 | Parameters | |||
|
29 | ---------- | |||
|
30 | nb : NotebookNode | |||
|
31 | The Python representation of the notebook to convert. | |||
|
32 | from_version : int | |||
|
33 | The original version of the notebook to convert. | |||
|
34 | from_minor : int | |||
|
35 | The original minor version of the notebook to convert (only relevant for v >= 3). | |||
|
36 | """ | |||
|
37 | if from_version == 3: | |||
|
38 | # Validate the notebook before conversion | |||
|
39 | _warn_if_invalid(nb, from_version) | |||
|
40 | ||||
|
41 | # Mark the original nbformat so consumers know it has been converted | |||
|
42 | orig_nbformat = nb.pop('orig_nbformat', None) | |||
|
43 | nb.metadata.orig_nbformat = orig_nbformat or 3 | |||
|
44 | ||||
|
45 | # Mark the new format | |||
|
46 | nb.nbformat = nbformat | |||
|
47 | nb.nbformat_minor = nbformat_minor | |||
|
48 | ||||
|
49 | # remove worksheet(s) | |||
|
50 | nb['cells'] = cells = [] | |||
|
51 | # In the unlikely event of multiple worksheets, | |||
|
52 | # they will be flattened | |||
|
53 | for ws in nb.pop('worksheets', []): | |||
|
54 | # upgrade each cell | |||
|
55 | for cell in ws['cells']: | |||
|
56 | cells.append(upgrade_cell(cell)) | |||
|
57 | # upgrade metadata | |||
|
58 | nb.metadata.pop('name', '') | |||
|
59 | # Validate the converted notebook before returning it | |||
|
60 | _warn_if_invalid(nb, nbformat) | |||
|
61 | return nb | |||
|
62 | elif from_version == 4: | |||
|
63 | # nothing to do | |||
|
64 | if from_minor != nbformat_minor: | |||
|
65 | nb.metadata.orig_nbformat_minor = from_minor | |||
|
66 | nb.nbformat_minor = nbformat_minor | |||
|
67 | ||||
|
68 | return nb | |||
|
69 | else: | |||
|
70 | raise ValueError('Cannot convert a notebook directly from v%s to v4. ' \ | |||
|
71 | 'Try using the IPython.nbformat.convert module.' % from_version) | |||
|
72 | ||||
|
73 | def upgrade_cell(cell): | |||
|
74 | """upgrade a cell from v3 to v4 | |||
|
75 | ||||
|
76 | heading cell -> markdown heading | |||
|
77 | code cell: | |||
|
78 | - remove language metadata | |||
|
79 | - cell.input -> cell.source | |||
|
80 | - cell.prompt_number -> cell.execution_count | |||
|
81 | - update outputs | |||
|
82 | """ | |||
|
83 | cell.setdefault('metadata', NotebookNode()) | |||
|
84 | if cell.cell_type == 'code': | |||
|
85 | cell.pop('language', '') | |||
|
86 | if 'collapsed' in cell: | |||
|
87 | cell.metadata['collapsed'] = cell.pop('collapsed') | |||
|
88 | cell.source = cell.pop('input', '') | |||
|
89 | cell.execution_count = cell.pop('prompt_number', None) | |||
|
90 | cell.outputs = upgrade_outputs(cell.outputs) | |||
|
91 | elif cell.cell_type == 'heading': | |||
|
92 | cell.cell_type = 'markdown' | |||
|
93 | level = cell.pop('level', 1) | |||
|
94 | cell.source = u'{hashes} {single_line}'.format( | |||
|
95 | hashes='#' * level, | |||
|
96 | single_line = ' '.join(cell.get('source', '').splitlines()), | |||
|
97 | ) | |||
|
98 | elif cell.cell_type == 'html': | |||
|
99 | # Technically, this exists. It will never happen in practice. | |||
|
100 | cell.cell_type = 'markdown' | |||
|
101 | return cell | |||
|
102 | ||||
|
103 | def downgrade_cell(cell): | |||
|
104 | """downgrade a cell from v4 to v3 | |||
|
105 | ||||
|
106 | code cell: | |||
|
107 | - set cell.language | |||
|
108 | - cell.input <- cell.source | |||
|
109 | - cell.prompt_number <- cell.execution_count | |||
|
110 | - update outputs | |||
|
111 | markdown cell: | |||
|
112 | - single-line heading -> heading cell | |||
|
113 | """ | |||
|
114 | if cell.cell_type == 'code': | |||
|
115 | cell.language = 'python' | |||
|
116 | cell.input = cell.pop('source', '') | |||
|
117 | cell.prompt_number = cell.pop('execution_count', None) | |||
|
118 | cell.collapsed = cell.metadata.pop('collapsed', False) | |||
|
119 | cell.outputs = downgrade_outputs(cell.outputs) | |||
|
120 | elif cell.cell_type == 'markdown': | |||
|
121 | source = cell.get('source', '') | |||
|
122 | if '\n' not in source and source.startswith('#'): | |||
|
123 | prefix, text = re.match(r'(#+)\s*(.*)', source).groups() | |||
|
124 | cell.cell_type = 'heading' | |||
|
125 | cell.source = text | |||
|
126 | cell.level = len(prefix) | |||
|
127 | return cell | |||
|
128 | ||||
|
129 | _mime_map = { | |||
|
130 | "text" : "text/plain", | |||
|
131 | "html" : "text/html", | |||
|
132 | "svg" : "image/svg+xml", | |||
|
133 | "png" : "image/png", | |||
|
134 | "jpeg" : "image/jpeg", | |||
|
135 | "latex" : "text/latex", | |||
|
136 | "json" : "application/json", | |||
|
137 | "javascript" : "application/javascript", | |||
|
138 | }; | |||
|
139 | ||||
|
140 | def to_mime_key(d): | |||
|
141 | """convert dict with v3 aliases to plain mime-type keys""" | |||
|
142 | for alias, mime in _mime_map.items(): | |||
|
143 | if alias in d: | |||
|
144 | d[mime] = d.pop(alias) | |||
|
145 | return d | |||
|
146 | ||||
|
147 | def from_mime_key(d): | |||
|
148 | """convert dict with mime-type keys to v3 aliases""" | |||
|
149 | for alias, mime in _mime_map.items(): | |||
|
150 | if mime in d: | |||
|
151 | d[alias] = d.pop(mime) | |||
|
152 | return d | |||
|
153 | ||||
|
154 | def upgrade_output(output): | |||
|
155 | """upgrade a single code cell output from v3 to v4 | |||
|
156 | ||||
|
157 | - pyout -> execute_result | |||
|
158 | - pyerr -> error | |||
|
159 | - output.type -> output.data.mime/type | |||
|
160 | - mime-type keys | |||
|
161 | - stream.stream -> stream.name | |||
|
162 | """ | |||
|
163 | if output['output_type'] in {'pyout', 'display_data'}: | |||
|
164 | output.setdefault('metadata', NotebookNode()) | |||
|
165 | if output['output_type'] == 'pyout': | |||
|
166 | output['output_type'] = 'execute_result' | |||
|
167 | output['execution_count'] = output.pop('prompt_number', None) | |||
|
168 | ||||
|
169 | # move output data into data sub-dict | |||
|
170 | data = {} | |||
|
171 | for key in list(output): | |||
|
172 | if key in {'output_type', 'execution_count', 'metadata'}: | |||
|
173 | continue | |||
|
174 | data[key] = output.pop(key) | |||
|
175 | to_mime_key(data) | |||
|
176 | output['data'] = data | |||
|
177 | to_mime_key(output.metadata) | |||
|
178 | if 'application/json' in data: | |||
|
179 | data['application/json'] = json.loads(data['application/json']) | |||
|
180 | # promote ascii bytes (from v2) to unicode | |||
|
181 | for key in ('image/png', 'image/jpeg'): | |||
|
182 | if key in data and isinstance(data[key], bytes): | |||
|
183 | data[key] = data[key].decode('ascii') | |||
|
184 | elif output['output_type'] == 'pyerr': | |||
|
185 | output['output_type'] = 'error' | |||
|
186 | elif output['output_type'] == 'stream': | |||
|
187 | output['name'] = output.pop('stream') | |||
|
188 | return output | |||
|
189 | ||||
|
190 | def downgrade_output(output): | |||
|
191 | """downgrade a single code cell output to v3 from v4 | |||
|
192 | ||||
|
193 | - pyout <- execute_result | |||
|
194 | - pyerr <- error | |||
|
195 | - output.data.mime/type -> output.type | |||
|
196 | - un-mime-type keys | |||
|
197 | - stream.stream <- stream.name | |||
|
198 | """ | |||
|
199 | if output['output_type'] in {'execute_result', 'display_data'}: | |||
|
200 | if output['output_type'] == 'execute_result': | |||
|
201 | output['output_type'] = 'pyout' | |||
|
202 | output['prompt_number'] = output.pop('execution_count', None) | |||
|
203 | ||||
|
204 | # promote data dict to top-level output namespace | |||
|
205 | data = output.pop('data', {}) | |||
|
206 | if 'application/json' in data: | |||
|
207 | data['application/json'] = json.dumps(data['application/json']) | |||
|
208 | from_mime_key(data) | |||
|
209 | output.update(data) | |||
|
210 | from_mime_key(output.get('metadata', {})) | |||
|
211 | elif output['output_type'] == 'error': | |||
|
212 | output['output_type'] = 'pyerr' | |||
|
213 | elif output['output_type'] == 'stream': | |||
|
214 | output['stream'] = output.pop('name') | |||
|
215 | return output | |||
|
216 | ||||
|
217 | def upgrade_outputs(outputs): | |||
|
218 | """upgrade outputs of a code cell from v3 to v4""" | |||
|
219 | return [upgrade_output(op) for op in outputs] | |||
|
220 | ||||
|
221 | def downgrade_outputs(outputs): | |||
|
222 | """downgrade outputs of a code cell to v3 from v4""" | |||
|
223 | return [downgrade_output(op) for op in outputs] | |||
|
224 | ||||
|
225 | def downgrade(nb): | |||
|
226 | """Convert a v4 notebook to v3. | |||
|
227 | ||||
|
228 | Parameters | |||
|
229 | ---------- | |||
|
230 | nb : NotebookNode | |||
|
231 | The Python representation of the notebook to convert. | |||
|
232 | """ | |||
|
233 | if nb.nbformat != nbformat: | |||
|
234 | return nb | |||
|
235 | ||||
|
236 | # Validate the notebook before conversion | |||
|
237 | _warn_if_invalid(nb, nbformat) | |||
|
238 | ||||
|
239 | nb.nbformat = v3.nbformat | |||
|
240 | nb.nbformat_minor = v3.nbformat_minor | |||
|
241 | cells = [ downgrade_cell(cell) for cell in nb.pop('cells') ] | |||
|
242 | nb.worksheets = [v3.new_worksheet(cells=cells)] | |||
|
243 | nb.metadata.setdefault('name', '') | |||
|
244 | nb.metadata.pop('orig_nbformat', None) | |||
|
245 | nb.metadata.pop('orig_nbformat_minor', None) | |||
|
246 | ||||
|
247 | # Validate the converted notebook before returning it | |||
|
248 | _warn_if_invalid(nb, v3.nbformat) | |||
|
249 | return nb |
@@ -0,0 +1,137 b'' | |||||
|
1 | """Python API for composing notebook elements | |||
|
2 | ||||
|
3 | The Python representation of a notebook is a nested structure of | |||
|
4 | dictionary subclasses that support attribute access | |||
|
5 | (IPython.utils.ipstruct.Struct). The functions in this module are merely | |||
|
6 | helpers to build the structs in the right form. | |||
|
7 | """ | |||
|
8 | ||||
|
9 | # Copyright (c) IPython Development Team. | |||
|
10 | # Distributed under the terms of the Modified BSD License. | |||
|
11 | ||||
|
12 | from ..notebooknode import from_dict, NotebookNode | |||
|
13 | ||||
|
14 | # Change this when incrementing the nbformat version | |||
|
15 | nbformat = 4 | |||
|
16 | nbformat_minor = 0 | |||
|
17 | nbformat_schema = 'nbformat.v4.schema.json' | |||
|
18 | ||||
|
19 | ||||
|
20 | def validate(node, ref=None): | |||
|
21 | """validate a v4 node""" | |||
|
22 | from .. import validate | |||
|
23 | return validate(node, ref=ref, version=nbformat) | |||
|
24 | ||||
|
25 | ||||
|
26 | def new_output(output_type, data=None, **kwargs): | |||
|
27 | """Create a new output, to go in the ``cell.outputs`` list of a code cell.""" | |||
|
28 | output = NotebookNode(output_type=output_type) | |||
|
29 | ||||
|
30 | # populate defaults: | |||
|
31 | if output_type == 'stream': | |||
|
32 | output.name = u'stdout' | |||
|
33 | output.text = u'' | |||
|
34 | elif output_type in {'execute_result', 'display_data'}: | |||
|
35 | output.metadata = NotebookNode() | |||
|
36 | output.data = NotebookNode() | |||
|
37 | # load from args: | |||
|
38 | output.update(from_dict(kwargs)) | |||
|
39 | if data is not None: | |||
|
40 | output.data = from_dict(data) | |||
|
41 | # validate | |||
|
42 | validate(output, output_type) | |||
|
43 | return output | |||
|
44 | ||||
|
45 | ||||
|
46 | def output_from_msg(msg): | |||
|
47 | """Create a NotebookNode for an output from a kernel's IOPub message. | |||
|
48 | ||||
|
49 | Returns | |||
|
50 | ------- | |||
|
51 | ||||
|
52 | NotebookNode: the output as a notebook node. | |||
|
53 | ||||
|
54 | Raises | |||
|
55 | ------ | |||
|
56 | ||||
|
57 | ValueError: if the message is not an output message. | |||
|
58 | ||||
|
59 | """ | |||
|
60 | msg_type = msg['header']['msg_type'] | |||
|
61 | content = msg['content'] | |||
|
62 | ||||
|
63 | if msg_type == 'execute_result': | |||
|
64 | return new_output(output_type=msg_type, | |||
|
65 | metadata=content['metadata'], | |||
|
66 | data=content['data'], | |||
|
67 | execution_count=content['execution_count'], | |||
|
68 | ) | |||
|
69 | elif msg_type == 'stream': | |||
|
70 | return new_output(output_type=msg_type, | |||
|
71 | name=content['name'], | |||
|
72 | text=content['text'], | |||
|
73 | ) | |||
|
74 | elif msg_type == 'display_data': | |||
|
75 | return new_output(output_type=msg_type, | |||
|
76 | metadata=content['metadata'], | |||
|
77 | data=content['data'], | |||
|
78 | ) | |||
|
79 | elif msg_type == 'error': | |||
|
80 | return new_output(output_type=msg_type, | |||
|
81 | ename=content['ename'], | |||
|
82 | evalue=content['evalue'], | |||
|
83 | traceback=content['traceback'], | |||
|
84 | ) | |||
|
85 | else: | |||
|
86 | raise ValueError("Unrecognized output msg type: %r" % msg_type) | |||
|
87 | ||||
|
88 | ||||
|
89 | def new_code_cell(source='', **kwargs): | |||
|
90 | """Create a new code cell""" | |||
|
91 | cell = NotebookNode( | |||
|
92 | cell_type='code', | |||
|
93 | metadata=NotebookNode(), | |||
|
94 | execution_count=None, | |||
|
95 | source=source, | |||
|
96 | outputs=[], | |||
|
97 | ) | |||
|
98 | cell.update(from_dict(kwargs)) | |||
|
99 | ||||
|
100 | validate(cell, 'code_cell') | |||
|
101 | return cell | |||
|
102 | ||||
|
103 | def new_markdown_cell(source='', **kwargs): | |||
|
104 | """Create a new markdown cell""" | |||
|
105 | cell = NotebookNode( | |||
|
106 | cell_type='markdown', | |||
|
107 | source=source, | |||
|
108 | metadata=NotebookNode(), | |||
|
109 | ) | |||
|
110 | cell.update(from_dict(kwargs)) | |||
|
111 | ||||
|
112 | validate(cell, 'markdown_cell') | |||
|
113 | return cell | |||
|
114 | ||||
|
115 | def new_raw_cell(source='', **kwargs): | |||
|
116 | """Create a new raw cell""" | |||
|
117 | cell = NotebookNode( | |||
|
118 | cell_type='raw', | |||
|
119 | source=source, | |||
|
120 | metadata=NotebookNode(), | |||
|
121 | ) | |||
|
122 | cell.update(from_dict(kwargs)) | |||
|
123 | ||||
|
124 | validate(cell, 'raw_cell') | |||
|
125 | return cell | |||
|
126 | ||||
|
127 | def new_notebook(**kwargs): | |||
|
128 | """Create a new notebook""" | |||
|
129 | nb = NotebookNode( | |||
|
130 | nbformat=nbformat, | |||
|
131 | nbformat_minor=nbformat_minor, | |||
|
132 | metadata=NotebookNode(), | |||
|
133 | cells=[], | |||
|
134 | ) | |||
|
135 | nb.update(from_dict(kwargs)) | |||
|
136 | validate(nb) | |||
|
137 | return nb |
@@ -0,0 +1,308 b'' | |||||
|
1 | { | |||
|
2 | "$schema": "http://json-schema.org/draft-04/schema#", | |||
|
3 | "description": "IPython Notebook v4.0 JSON schema.", | |||
|
4 | "type": "object", | |||
|
5 | "additionalProperties": false, | |||
|
6 | "required": ["metadata", "nbformat_minor", "nbformat", "cells"], | |||
|
7 | "properties": { | |||
|
8 | "metadata": { | |||
|
9 | "description": "Notebook root-level metadata.", | |||
|
10 | "type": "object", | |||
|
11 | "additionalProperties": true, | |||
|
12 | "properties": { | |||
|
13 | "kernel_info": { | |||
|
14 | "description": "Kernel information.", | |||
|
15 | "type": "object", | |||
|
16 | "required": ["name", "language"], | |||
|
17 | "properties": { | |||
|
18 | "name": { | |||
|
19 | "description": "Name of the kernel specification.", | |||
|
20 | "type": "string" | |||
|
21 | }, | |||
|
22 | "language": { | |||
|
23 | "description": "The programming language which this kernel runs.", | |||
|
24 | "type": "string" | |||
|
25 | }, | |||
|
26 | "codemirror_mode": { | |||
|
27 | "description": "The codemirror mode to use for code in this language.", | |||
|
28 | "type": "string" | |||
|
29 | } | |||
|
30 | } | |||
|
31 | }, | |||
|
32 | "signature": { | |||
|
33 | "description": "Hash of the notebook.", | |||
|
34 | "type": "string" | |||
|
35 | }, | |||
|
36 | "orig_nbformat": { | |||
|
37 | "description": "Original notebook format (major number) before converting the notebook between versions. This should never be written to a file.", | |||
|
38 | "type": "integer", | |||
|
39 | "minimum": 1 | |||
|
40 | } | |||
|
41 | } | |||
|
42 | }, | |||
|
43 | "nbformat_minor": { | |||
|
44 | "description": "Notebook format (minor number). Incremented for backward compatible changes to the notebook format.", | |||
|
45 | "type": "integer", | |||
|
46 | "minimum": 0 | |||
|
47 | }, | |||
|
48 | "nbformat": { | |||
|
49 | "description": "Notebook format (major number). Incremented between backwards incompatible changes to the notebook format.", | |||
|
50 | "type": "integer", | |||
|
51 | "minimum": 4, | |||
|
52 | "maximum": 4 | |||
|
53 | }, | |||
|
54 | "cells": { | |||
|
55 | "description": "Array of cells of the current notebook.", | |||
|
56 | "type": "array", | |||
|
57 | "items": { | |||
|
58 | "type": "object", | |||
|
59 | "oneOf": [ | |||
|
60 | {"$ref": "#/definitions/raw_cell"}, | |||
|
61 | {"$ref": "#/definitions/markdown_cell"}, | |||
|
62 | {"$ref": "#/definitions/code_cell"} | |||
|
63 | ] | |||
|
64 | } | |||
|
65 | } | |||
|
66 | }, | |||
|
67 | ||||
|
68 | "definitions": { | |||
|
69 | ||||
|
70 | "raw_cell": { | |||
|
71 | "description": "Notebook raw nbconvert cell.", | |||
|
72 | "type": "object", | |||
|
73 | "additionalProperties": false, | |||
|
74 | "required": ["cell_type", "metadata", "source"], | |||
|
75 | "properties": { | |||
|
76 | "cell_type": { | |||
|
77 | "description": "String identifying the type of cell.", | |||
|
78 | "enum": ["raw"] | |||
|
79 | }, | |||
|
80 | "metadata": { | |||
|
81 | "description": "Cell-level metadata.", | |||
|
82 | "type": "object", | |||
|
83 | "additionalProperties": true, | |||
|
84 | "properties": { | |||
|
85 | "format": { | |||
|
86 | "description": "Raw cell metadata format for nbconvert.", | |||
|
87 | "type": "string" | |||
|
88 | }, | |||
|
89 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |||
|
90 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |||
|
91 | } | |||
|
92 | }, | |||
|
93 | "source": {"$ref": "#/definitions/misc/source"} | |||
|
94 | } | |||
|
95 | }, | |||
|
96 | ||||
|
97 | "markdown_cell": { | |||
|
98 | "description": "Notebook markdown cell.", | |||
|
99 | "type": "object", | |||
|
100 | "additionalProperties": false, | |||
|
101 | "required": ["cell_type", "metadata", "source"], | |||
|
102 | "properties": { | |||
|
103 | "cell_type": { | |||
|
104 | "description": "String identifying the type of cell.", | |||
|
105 | "enum": ["markdown"] | |||
|
106 | }, | |||
|
107 | "metadata": { | |||
|
108 | "description": "Cell-level metadata.", | |||
|
109 | "type": "object", | |||
|
110 | "properties": { | |||
|
111 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |||
|
112 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |||
|
113 | }, | |||
|
114 | "additionalProperties": true | |||
|
115 | }, | |||
|
116 | "source": {"$ref": "#/definitions/misc/source"} | |||
|
117 | } | |||
|
118 | }, | |||
|
119 | ||||
|
120 | "code_cell": { | |||
|
121 | "description": "Notebook code cell.", | |||
|
122 | "type": "object", | |||
|
123 | "additionalProperties": false, | |||
|
124 | "required": ["cell_type", "metadata", "source", "outputs", "execution_count"], | |||
|
125 | "properties": { | |||
|
126 | "cell_type": { | |||
|
127 | "description": "String identifying the type of cell.", | |||
|
128 | "enum": ["code"] | |||
|
129 | }, | |||
|
130 | "metadata": { | |||
|
131 | "description": "Cell-level metadata.", | |||
|
132 | "type": "object", | |||
|
133 | "additionalProperties": true, | |||
|
134 | "properties": { | |||
|
135 | "collapsed": { | |||
|
136 | "description": "Whether the cell is collapsed/expanded.", | |||
|
137 | "type": "boolean" | |||
|
138 | }, | |||
|
139 | "autoscroll": { | |||
|
140 | "description": "Whether the cell's output is scrolled, unscrolled, or autoscrolled.", | |||
|
141 | "enum": [true, false, "auto"] | |||
|
142 | }, | |||
|
143 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |||
|
144 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |||
|
145 | } | |||
|
146 | }, | |||
|
147 | "source": {"$ref": "#/definitions/misc/source"}, | |||
|
148 | "outputs": { | |||
|
149 | "description": "Execution, display, or stream outputs.", | |||
|
150 | "type": "array", | |||
|
151 | "items": {"$ref": "#/definitions/output"} | |||
|
152 | }, | |||
|
153 | "execution_count": { | |||
|
154 | "description": "The code cell's prompt number. Will be null if the cell has not been run.", | |||
|
155 | "type": ["integer", "null"], | |||
|
156 | "minimum": 0 | |||
|
157 | } | |||
|
158 | } | |||
|
159 | }, | |||
|
160 | "output": { | |||
|
161 | "type": "object", | |||
|
162 | "oneOf": [ | |||
|
163 | {"$ref": "#/definitions/execute_result"}, | |||
|
164 | {"$ref": "#/definitions/display_data"}, | |||
|
165 | {"$ref": "#/definitions/stream"}, | |||
|
166 | {"$ref": "#/definitions/error"} | |||
|
167 | ] | |||
|
168 | }, | |||
|
169 | ||||
|
170 | "execute_result": { | |||
|
171 | "description": "Result of executing a code cell.", | |||
|
172 | "type": "object", | |||
|
173 | "additionalProperties": false, | |||
|
174 | "required": ["output_type", "data", "metadata", "execution_count"], | |||
|
175 | "properties": { | |||
|
176 | "output_type": { | |||
|
177 | "description": "Type of cell output.", | |||
|
178 | "enum": ["execute_result"] | |||
|
179 | }, | |||
|
180 | "execution_count": { | |||
|
181 | "description": "A result's prompt number.", | |||
|
182 | "type": ["integer", "null"], | |||
|
183 | "minimum": 0 | |||
|
184 | }, | |||
|
185 | "data": {"$ref": "#/definitions/misc/mimebundle"}, | |||
|
186 | "metadata": {"$ref": "#/definitions/misc/output_metadata"} | |||
|
187 | } | |||
|
188 | }, | |||
|
189 | ||||
|
190 | "display_data": { | |||
|
191 | "description": "Data displayed as a result of code cell execution.", | |||
|
192 | "type": "object", | |||
|
193 | "additionalProperties": false, | |||
|
194 | "required": ["output_type", "data", "metadata"], | |||
|
195 | "properties": { | |||
|
196 | "output_type": { | |||
|
197 | "description": "Type of cell output.", | |||
|
198 | "enum": ["display_data"] | |||
|
199 | }, | |||
|
200 | "data": {"$ref": "#/definitions/misc/mimebundle"}, | |||
|
201 | "metadata": {"$ref": "#/definitions/misc/output_metadata"} | |||
|
202 | } | |||
|
203 | }, | |||
|
204 | ||||
|
205 | "stream": { | |||
|
206 | "description": "Stream output from a code cell.", | |||
|
207 | "type": "object", | |||
|
208 | "additionalProperties": false, | |||
|
209 | "required": ["output_type", "name", "text"], | |||
|
210 | "properties": { | |||
|
211 | "output_type": { | |||
|
212 | "description": "Type of cell output.", | |||
|
213 | "enum": ["stream"] | |||
|
214 | }, | |||
|
215 | "name": { | |||
|
216 | "description": "The name of the stream (stdout, stderr).", | |||
|
217 | "type": "string" | |||
|
218 | }, | |||
|
219 | "text": { | |||
|
220 | "description": "The stream's text output, represented as an array of strings.", | |||
|
221 | "$ref": "#/definitions/misc/multiline_string" | |||
|
222 | } | |||
|
223 | } | |||
|
224 | }, | |||
|
225 | ||||
|
226 | "error": { | |||
|
227 | "description": "Output of an error that occurred during code cell execution.", | |||
|
228 | "type": "object", | |||
|
229 | "additionalProperties": false, | |||
|
230 | "required": ["output_type", "ename", "evalue", "traceback"], | |||
|
231 | "properties": { | |||
|
232 | "output_type": { | |||
|
233 | "description": "Type of cell output.", | |||
|
234 | "enum": ["error"] | |||
|
235 | }, | |||
|
236 | "ename": { | |||
|
237 | "description": "The name of the error.", | |||
|
238 | "type": "string" | |||
|
239 | }, | |||
|
240 | "evalue": { | |||
|
241 | "description": "The value, or message, of the error.", | |||
|
242 | "type": "string" | |||
|
243 | }, | |||
|
244 | "traceback": { | |||
|
245 | "description": "The error's traceback, represented as an array of strings.", | |||
|
246 | "type": "array", | |||
|
247 | "items": {"type": "string"} | |||
|
248 | } | |||
|
249 | } | |||
|
250 | }, | |||
|
251 | ||||
|
252 | "misc": { | |||
|
253 | "metadata_name": { | |||
|
254 | "description": "The cell's name. If present, must be a non-empty string.", | |||
|
255 | "type": "string", | |||
|
256 | "pattern": "^.+$" | |||
|
257 | }, | |||
|
258 | "metadata_tags": { | |||
|
259 | "description": "The cell's tags. Tags must be unique, and must not contain commas.", | |||
|
260 | "type": "array", | |||
|
261 | "uniqueItems": true, | |||
|
262 | "items": { | |||
|
263 | "type": "string", | |||
|
264 | "pattern": "^[^,]+$" | |||
|
265 | } | |||
|
266 | }, | |||
|
267 | "source": { | |||
|
268 | "description": "Contents of the cell, represented as an array of lines.", | |||
|
269 | "$ref": "#/definitions/misc/multiline_string" | |||
|
270 | }, | |||
|
271 | "execution_count": { | |||
|
272 | "description": "The code cell's prompt number. Will be null if the cell has not been run.", | |||
|
273 | "type": ["integer", "null"], | |||
|
274 | "minimum": 0 | |||
|
275 | }, | |||
|
276 | "mimebundle": { | |||
|
277 | "description": "A mime-type keyed dictionary of data", | |||
|
278 | "type": "object", | |||
|
279 | "additionalProperties": false, | |||
|
280 | "properties": { | |||
|
281 | "application/json": { | |||
|
282 | "type": "object" | |||
|
283 | } | |||
|
284 | }, | |||
|
285 | "patternProperties": { | |||
|
286 | "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { | |||
|
287 | "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", | |||
|
288 | "$ref": "#/definitions/misc/multiline_string" | |||
|
289 | } | |||
|
290 | } | |||
|
291 | }, | |||
|
292 | "output_metadata": { | |||
|
293 | "description": "Cell output metadata.", | |||
|
294 | "type": "object", | |||
|
295 | "additionalProperties": true | |||
|
296 | }, | |||
|
297 | "multiline_string": { | |||
|
298 | "oneOf" : [ | |||
|
299 | {"type": "string"}, | |||
|
300 | { | |||
|
301 | "type": "array", | |||
|
302 | "items": {"type": "string"} | |||
|
303 | } | |||
|
304 | ] | |||
|
305 | } | |||
|
306 | } | |||
|
307 | } | |||
|
308 | } |
@@ -0,0 +1,67 b'' | |||||
|
1 | """Read and write notebooks in JSON format.""" | |||
|
2 | ||||
|
3 | # Copyright (c) IPython Development Team. | |||
|
4 | # Distributed under the terms of the Modified BSD License. | |||
|
5 | ||||
|
6 | import copy | |||
|
7 | import json | |||
|
8 | ||||
|
9 | from IPython.utils import py3compat | |||
|
10 | ||||
|
11 | from .nbbase import from_dict | |||
|
12 | from .rwbase import ( | |||
|
13 | NotebookReader, NotebookWriter, rejoin_lines, split_lines, strip_transient | |||
|
14 | ) | |||
|
15 | ||||
|
16 | ||||
|
17 | class BytesEncoder(json.JSONEncoder): | |||
|
18 | """A JSON encoder that accepts b64 (and other *ascii*) bytestrings.""" | |||
|
19 | def default(self, obj): | |||
|
20 | if isinstance(obj, bytes): | |||
|
21 | return obj.decode('ascii') | |||
|
22 | return json.JSONEncoder.default(self, obj) | |||
|
23 | ||||
|
24 | ||||
|
25 | class JSONReader(NotebookReader): | |||
|
26 | ||||
|
27 | def reads(self, s, **kwargs): | |||
|
28 | """Read a JSON string into a Notebook object""" | |||
|
29 | nb = json.loads(s, **kwargs) | |||
|
30 | nb = self.to_notebook(nb, **kwargs) | |||
|
31 | return nb | |||
|
32 | ||||
|
33 | def to_notebook(self, d, **kwargs): | |||
|
34 | """Convert a disk-format notebook dict to in-memory NotebookNode | |||
|
35 | ||||
|
36 | handles multi-line values as strings, scrubbing of transient values, etc. | |||
|
37 | """ | |||
|
38 | nb = from_dict(d) | |||
|
39 | nb = rejoin_lines(nb) | |||
|
40 | nb = strip_transient(nb) | |||
|
41 | return nb | |||
|
42 | ||||
|
43 | ||||
|
44 | class JSONWriter(NotebookWriter): | |||
|
45 | ||||
|
46 | def writes(self, nb, **kwargs): | |||
|
47 | """Serialize a NotebookNode object as a JSON string""" | |||
|
48 | kwargs['cls'] = BytesEncoder | |||
|
49 | kwargs['indent'] = 1 | |||
|
50 | kwargs['sort_keys'] = True | |||
|
51 | kwargs['separators'] = (',',': ') | |||
|
52 | # don't modify in-memory dict | |||
|
53 | nb = copy.deepcopy(nb) | |||
|
54 | if kwargs.pop('split_lines', True): | |||
|
55 | nb = split_lines(nb) | |||
|
56 | nb = strip_transient(nb) | |||
|
57 | return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8') | |||
|
58 | ||||
|
59 | ||||
|
60 | _reader = JSONReader() | |||
|
61 | _writer = JSONWriter() | |||
|
62 | ||||
|
63 | reads = _reader.reads | |||
|
64 | read = _reader.read | |||
|
65 | to_notebook = _reader.to_notebook | |||
|
66 | write = _writer.write | |||
|
67 | writes = _writer.writes |
@@ -0,0 +1,95 b'' | |||||
|
1 | """Base classes and utilities for readers and writers.""" | |||
|
2 | ||||
|
3 | # Copyright (c) IPython Development Team. | |||
|
4 | # Distributed under the terms of the Modified BSD License. | |||
|
5 | ||||
|
6 | from IPython.utils.py3compat import string_types, cast_unicode_py2 | |||
|
7 | ||||
|
8 | ||||
|
9 | def rejoin_lines(nb): | |||
|
10 | """rejoin multiline text into strings | |||
|
11 | ||||
|
12 | For reversing effects of ``split_lines(nb)``. | |||
|
13 | ||||
|
14 | This only rejoins lines that have been split, so if text objects were not split | |||
|
15 | they will pass through unchanged. | |||
|
16 | ||||
|
17 | Used when reading JSON files that may have been passed through split_lines. | |||
|
18 | """ | |||
|
19 | for cell in nb.cells: | |||
|
20 | if 'source' in cell and isinstance(cell.source, list): | |||
|
21 | cell.source = ''.join(cell.source) | |||
|
22 | if cell.get('cell_type', None) == 'code': | |||
|
23 | for output in cell.get('outputs', []): | |||
|
24 | output_type = output.get('output_type', '') | |||
|
25 | if output_type in {'execute_result', 'display_data'}: | |||
|
26 | for key, value in output.get('data', {}).items(): | |||
|
27 | if key != 'application/json' and isinstance(value, list): | |||
|
28 | output.data[key] = ''.join(value) | |||
|
29 | elif output_type: | |||
|
30 | if isinstance(output.get('text', ''), list): | |||
|
31 | output.text = ''.join(output.text) | |||
|
32 | return nb | |||
|
33 | ||||
|
34 | ||||
|
35 | def split_lines(nb): | |||
|
36 | """split likely multiline text into lists of strings | |||
|
37 | ||||
|
38 | For file output more friendly to line-based VCS. ``rejoin_lines(nb)`` will | |||
|
39 | reverse the effects of ``split_lines(nb)``. | |||
|
40 | ||||
|
41 | Used when writing JSON files. | |||
|
42 | """ | |||
|
43 | for cell in nb.cells: | |||
|
44 | source = cell.get('source', None) | |||
|
45 | if isinstance(source, string_types): | |||
|
46 | cell['source'] = source.splitlines(True) | |||
|
47 | ||||
|
48 | if cell.cell_type == 'code': | |||
|
49 | for output in cell.outputs: | |||
|
50 | if output.output_type in {'execute_result', 'display_data'}: | |||
|
51 | for key, value in output.data.items(): | |||
|
52 | if key != 'application/json' and isinstance(value, string_types): | |||
|
53 | output.data[key] = value.splitlines(True) | |||
|
54 | elif output.output_type == 'stream': | |||
|
55 | if isinstance(output.text, string_types): | |||
|
56 | output.text = output.text.splitlines(True) | |||
|
57 | return nb | |||
|
58 | ||||
|
59 | ||||
|
60 | def strip_transient(nb): | |||
|
61 | """Strip transient values that shouldn't be stored in files. | |||
|
62 | ||||
|
63 | This should be called in *both* read and write. | |||
|
64 | """ | |||
|
65 | nb.metadata.pop('orig_nbformat', None) | |||
|
66 | nb.metadata.pop('orig_nbformat_minor', None) | |||
|
67 | for cell in nb.cells: | |||
|
68 | cell.metadata.pop('trusted', None) | |||
|
69 | return nb | |||
|
70 | ||||
|
71 | ||||
|
72 | class NotebookReader(object): | |||
|
73 | """A class for reading notebooks.""" | |||
|
74 | ||||
|
75 | def reads(self, s, **kwargs): | |||
|
76 | """Read a notebook from a string.""" | |||
|
77 | raise NotImplementedError("loads must be implemented in a subclass") | |||
|
78 | ||||
|
79 | def read(self, fp, **kwargs): | |||
|
80 | """Read a notebook from a file like object""" | |||
|
81 | nbs = cast_unicode_py2(fp.read()) | |||
|
82 | return self.reads(nbs, **kwargs) | |||
|
83 | ||||
|
84 | ||||
|
85 | class NotebookWriter(object): | |||
|
86 | """A class for writing notebooks.""" | |||
|
87 | ||||
|
88 | def writes(self, nb, **kwargs): | |||
|
89 | """Write a notebook to a string.""" | |||
|
90 | raise NotImplementedError("loads must be implemented in a subclass") | |||
|
91 | ||||
|
92 | def write(self, nb, fp, **kwargs): | |||
|
93 | """Write a notebook to a file like object""" | |||
|
94 | nbs = cast_unicode_py2(self.writes(nb, **kwargs)) | |||
|
95 | return fp.write(nbs) |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
@@ -0,0 +1,54 b'' | |||||
|
1 | # -*- coding: utf8 -*- | |||
|
2 | import io | |||
|
3 | import os | |||
|
4 | import shutil | |||
|
5 | import tempfile | |||
|
6 | ||||
|
7 | pjoin = os.path.join | |||
|
8 | ||||
|
9 | from .nbexamples import nb0 | |||
|
10 | ||||
|
11 | ||||
|
12 | def open_utf8(fname, mode): | |||
|
13 | return io.open(fname, mode=mode, encoding='utf-8') | |||
|
14 | ||||
|
15 | class NBFormatTest: | |||
|
16 | """Mixin for writing notebook format tests""" | |||
|
17 | ||||
|
18 | # override with appropriate values in subclasses | |||
|
19 | nb0_ref = None | |||
|
20 | ext = None | |||
|
21 | mod = None | |||
|
22 | ||||
|
23 | def setUp(self): | |||
|
24 | self.wd = tempfile.mkdtemp() | |||
|
25 | ||||
|
26 | def tearDown(self): | |||
|
27 | shutil.rmtree(self.wd) | |||
|
28 | ||||
|
29 | def assertNBEquals(self, nba, nbb): | |||
|
30 | self.assertEqual(nba, nbb) | |||
|
31 | ||||
|
32 | def test_writes(self): | |||
|
33 | s = self.mod.writes(nb0) | |||
|
34 | if self.nb0_ref: | |||
|
35 | self.assertEqual(s, self.nb0_ref) | |||
|
36 | ||||
|
37 | def test_reads(self): | |||
|
38 | s = self.mod.writes(nb0) | |||
|
39 | nb = self.mod.reads(s) | |||
|
40 | ||||
|
41 | def test_roundtrip(self): | |||
|
42 | s = self.mod.writes(nb0) | |||
|
43 | self.assertNBEquals(self.mod.reads(s),nb0) | |||
|
44 | ||||
|
45 | def test_write_file(self): | |||
|
46 | with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'w') as f: | |||
|
47 | self.mod.write(nb0, f) | |||
|
48 | ||||
|
49 | def test_read_file(self): | |||
|
50 | with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'w') as f: | |||
|
51 | self.mod.write(nb0, f) | |||
|
52 | ||||
|
53 | with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'r') as f: | |||
|
54 | nb = self.mod.read(f) |
@@ -0,0 +1,104 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | import os | |||
|
4 | from base64 import encodestring | |||
|
5 | ||||
|
6 | from ..nbbase import ( | |||
|
7 | new_code_cell, new_markdown_cell, new_notebook, | |||
|
8 | new_output, new_raw_cell | |||
|
9 | ) | |||
|
10 | ||||
|
11 | # some random base64-encoded *text* | |||
|
12 | png = encodestring(os.urandom(5)).decode('ascii') | |||
|
13 | jpeg = encodestring(os.urandom(6)).decode('ascii') | |||
|
14 | ||||
|
15 | cells = [] | |||
|
16 | cells.append(new_markdown_cell( | |||
|
17 | source='Some NumPy Examples', | |||
|
18 | )) | |||
|
19 | ||||
|
20 | ||||
|
21 | cells.append(new_code_cell( | |||
|
22 | source='import numpy', | |||
|
23 | execution_count=1, | |||
|
24 | )) | |||
|
25 | ||||
|
26 | cells.append(new_markdown_cell( | |||
|
27 | source='A random array', | |||
|
28 | )) | |||
|
29 | ||||
|
30 | cells.append(new_raw_cell( | |||
|
31 | source='A random array', | |||
|
32 | )) | |||
|
33 | ||||
|
34 | cells.append(new_markdown_cell( | |||
|
35 | source=u'## My Heading', | |||
|
36 | )) | |||
|
37 | ||||
|
38 | cells.append(new_code_cell( | |||
|
39 | source='a = numpy.random.rand(100)', | |||
|
40 | execution_count=2, | |||
|
41 | )) | |||
|
42 | cells.append(new_code_cell( | |||
|
43 | source='a = 10\nb = 5\n', | |||
|
44 | execution_count=3, | |||
|
45 | )) | |||
|
46 | cells.append(new_code_cell( | |||
|
47 | source='a = 10\nb = 5', | |||
|
48 | execution_count=4, | |||
|
49 | )) | |||
|
50 | ||||
|
51 | cells.append(new_code_cell( | |||
|
52 | source=u'print "ünîcødé"', | |||
|
53 | execution_count=3, | |||
|
54 | outputs=[new_output( | |||
|
55 | output_type=u'execute_result', | |||
|
56 | data={ | |||
|
57 | 'text/plain': u'<array a>', | |||
|
58 | 'text/html': u'The HTML rep', | |||
|
59 | 'text/latex': u'$a$', | |||
|
60 | 'image/png': png, | |||
|
61 | 'image/jpeg': jpeg, | |||
|
62 | 'image/svg+xml': u'<svg>', | |||
|
63 | 'application/json': { | |||
|
64 | 'key': 'value' | |||
|
65 | }, | |||
|
66 | 'application/javascript': u'var i=0;' | |||
|
67 | }, | |||
|
68 | execution_count=3 | |||
|
69 | ),new_output( | |||
|
70 | output_type=u'display_data', | |||
|
71 | data={ | |||
|
72 | 'text/plain': u'<array a>', | |||
|
73 | 'text/html': u'The HTML rep', | |||
|
74 | 'text/latex': u'$a$', | |||
|
75 | 'image/png': png, | |||
|
76 | 'image/jpeg': jpeg, | |||
|
77 | 'image/svg+xml': u'<svg>', | |||
|
78 | 'application/json': { | |||
|
79 | 'key': 'value' | |||
|
80 | }, | |||
|
81 | 'application/javascript': u'var i=0;' | |||
|
82 | }, | |||
|
83 | ),new_output( | |||
|
84 | output_type=u'error', | |||
|
85 | ename=u'NameError', | |||
|
86 | evalue=u'NameError was here', | |||
|
87 | traceback=[u'frame 0', u'frame 1', u'frame 2'] | |||
|
88 | ),new_output( | |||
|
89 | output_type=u'stream', | |||
|
90 | text='foo\rbar\r\n' | |||
|
91 | ),new_output( | |||
|
92 | output_type=u'stream', | |||
|
93 | name='stderr', | |||
|
94 | text='\rfoo\rbar\n' | |||
|
95 | )] | |||
|
96 | )) | |||
|
97 | ||||
|
98 | nb0 = new_notebook(cells=cells, | |||
|
99 | metadata={ | |||
|
100 | 'language': 'python', | |||
|
101 | } | |||
|
102 | ) | |||
|
103 | ||||
|
104 |
@@ -0,0 +1,72 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | import copy | |||
|
3 | ||||
|
4 | import nose.tools as nt | |||
|
5 | ||||
|
6 | from IPython.nbformat import validate | |||
|
7 | from .. import convert | |||
|
8 | ||||
|
9 | from . import nbexamples | |||
|
10 | from IPython.nbformat.v3.tests import nbexamples as v3examples | |||
|
11 | from IPython.nbformat import v3, v4 | |||
|
12 | ||||
|
13 | def test_upgrade_notebook(): | |||
|
14 | nb03 = copy.deepcopy(v3examples.nb0) | |||
|
15 | validate(nb03) | |||
|
16 | nb04 = convert.upgrade(nb03) | |||
|
17 | validate(nb04) | |||
|
18 | ||||
|
19 | def test_downgrade_notebook(): | |||
|
20 | nb04 = copy.deepcopy(nbexamples.nb0) | |||
|
21 | validate(nb04) | |||
|
22 | nb03 = convert.downgrade(nb04) | |||
|
23 | validate(nb03) | |||
|
24 | ||||
|
25 | def test_upgrade_heading(): | |||
|
26 | v3h = v3.new_heading_cell | |||
|
27 | v4m = v4.new_markdown_cell | |||
|
28 | for v3cell, expected in [ | |||
|
29 | ( | |||
|
30 | v3h(source='foo', level=1), | |||
|
31 | v4m(source='# foo'), | |||
|
32 | ), | |||
|
33 | ( | |||
|
34 | v3h(source='foo\nbar\nmulti-line\n', level=4), | |||
|
35 | v4m(source='#### foo bar multi-line'), | |||
|
36 | ), | |||
|
37 | ( | |||
|
38 | v3h(source=u'ünìcö∂e–cønvërsioñ', level=4), | |||
|
39 | v4m(source=u'#### ünìcö∂e–cønvërsioñ'), | |||
|
40 | ), | |||
|
41 | ]: | |||
|
42 | upgraded = convert.upgrade_cell(v3cell) | |||
|
43 | nt.assert_equal(upgraded, expected) | |||
|
44 | ||||
|
45 | def test_downgrade_heading(): | |||
|
46 | v3h = v3.new_heading_cell | |||
|
47 | v4m = v4.new_markdown_cell | |||
|
48 | v3m = lambda source: v3.new_text_cell('markdown', source) | |||
|
49 | for v4cell, expected in [ | |||
|
50 | ( | |||
|
51 | v4m(source='# foo'), | |||
|
52 | v3h(source='foo', level=1), | |||
|
53 | ), | |||
|
54 | ( | |||
|
55 | v4m(source='#foo'), | |||
|
56 | v3h(source='foo', level=1), | |||
|
57 | ), | |||
|
58 | ( | |||
|
59 | v4m(source='#\tfoo'), | |||
|
60 | v3h(source='foo', level=1), | |||
|
61 | ), | |||
|
62 | ( | |||
|
63 | v4m(source='# \t foo'), | |||
|
64 | v3h(source='foo', level=1), | |||
|
65 | ), | |||
|
66 | ( | |||
|
67 | v4m(source='# foo\nbar'), | |||
|
68 | v3m(source='# foo\nbar'), | |||
|
69 | ), | |||
|
70 | ]: | |||
|
71 | downgraded = convert.downgrade_cell(v4cell) | |||
|
72 | nt.assert_equal(downgraded, expected) |
@@ -0,0 +1,69 b'' | |||||
|
1 | from base64 import decodestring | |||
|
2 | from unittest import TestCase | |||
|
3 | ||||
|
4 | from IPython.utils.py3compat import unicode_type | |||
|
5 | from ..nbjson import reads, writes | |||
|
6 | from .. import nbjson | |||
|
7 | from .nbexamples import nb0 | |||
|
8 | ||||
|
9 | from . import formattest | |||
|
10 | ||||
|
11 | ||||
|
12 | class TestJSON(formattest.NBFormatTest, TestCase): | |||
|
13 | ||||
|
14 | nb0_ref = None | |||
|
15 | ext = 'ipynb' | |||
|
16 | mod = nbjson | |||
|
17 | ||||
|
18 | def test_roundtrip_nosplit(self): | |||
|
19 | """Ensure that multiline blobs are still readable""" | |||
|
20 | # ensures that notebooks written prior to splitlines change | |||
|
21 | # are still readable. | |||
|
22 | s = writes(nb0, split_lines=False) | |||
|
23 | self.assertEqual(nbjson.reads(s),nb0) | |||
|
24 | ||||
|
25 | def test_roundtrip_split(self): | |||
|
26 | """Ensure that splitting multiline blocks is safe""" | |||
|
27 | # This won't differ from test_roundtrip unless the default changes | |||
|
28 | s = writes(nb0, split_lines=True) | |||
|
29 | self.assertEqual(nbjson.reads(s),nb0) | |||
|
30 | ||||
|
31 | def test_read_png(self): | |||
|
32 | """PNG output data is b64 unicode""" | |||
|
33 | s = writes(nb0) | |||
|
34 | nb1 = nbjson.reads(s) | |||
|
35 | found_png = False | |||
|
36 | for cell in nb1.cells: | |||
|
37 | if not 'outputs' in cell: | |||
|
38 | continue | |||
|
39 | for output in cell.outputs: | |||
|
40 | if not 'data' in output: | |||
|
41 | continue | |||
|
42 | if 'image/png' in output.data: | |||
|
43 | found_png = True | |||
|
44 | pngdata = output.data['image/png'] | |||
|
45 | self.assertEqual(type(pngdata), unicode_type) | |||
|
46 | # test that it is valid b64 data | |||
|
47 | b64bytes = pngdata.encode('ascii') | |||
|
48 | raw_bytes = decodestring(b64bytes) | |||
|
49 | assert found_png, "never found png output" | |||
|
50 | ||||
|
51 | def test_read_jpeg(self): | |||
|
52 | """JPEG output data is b64 unicode""" | |||
|
53 | s = writes(nb0) | |||
|
54 | nb1 = nbjson.reads(s) | |||
|
55 | found_jpeg = False | |||
|
56 | for cell in nb1.cells: | |||
|
57 | if not 'outputs' in cell: | |||
|
58 | continue | |||
|
59 | for output in cell.outputs: | |||
|
60 | if not 'data' in output: | |||
|
61 | continue | |||
|
62 | if 'image/jpeg' in output.data: | |||
|
63 | found_jpeg = True | |||
|
64 | jpegdata = output.data['image/jpeg'] | |||
|
65 | self.assertEqual(type(jpegdata), unicode_type) | |||
|
66 | # test that it is valid b64 data | |||
|
67 | b64bytes = jpegdata.encode('ascii') | |||
|
68 | raw_bytes = decodestring(b64bytes) | |||
|
69 | assert found_jpeg, "never found jpeg output" |
@@ -0,0 +1,101 b'' | |||||
|
1 | # coding: utf-8 | |||
|
2 | """Tests for the Python API for composing notebook elements""" | |||
|
3 | ||||
|
4 | import nose.tools as nt | |||
|
5 | ||||
|
6 | from IPython.nbformat.validator import isvalid, validate, ValidationError | |||
|
7 | from ..nbbase import ( | |||
|
8 | NotebookNode, nbformat, | |||
|
9 | new_code_cell, new_markdown_cell, new_notebook, | |||
|
10 | new_output, new_raw_cell, | |||
|
11 | ) | |||
|
12 | ||||
|
13 | def test_empty_notebook(): | |||
|
14 | nb = new_notebook() | |||
|
15 | nt.assert_equal(nb.cells, []) | |||
|
16 | nt.assert_equal(nb.metadata, NotebookNode()) | |||
|
17 | nt.assert_equal(nb.nbformat, nbformat) | |||
|
18 | ||||
|
19 | def test_empty_markdown_cell(): | |||
|
20 | cell = new_markdown_cell() | |||
|
21 | nt.assert_equal(cell.cell_type, 'markdown') | |||
|
22 | nt.assert_equal(cell.source, '') | |||
|
23 | ||||
|
24 | def test_markdown_cell(): | |||
|
25 | cell = new_markdown_cell(u'* Søme markdown') | |||
|
26 | nt.assert_equal(cell.source, u'* Søme markdown') | |||
|
27 | ||||
|
28 | def test_empty_raw_cell(): | |||
|
29 | cell = new_raw_cell() | |||
|
30 | nt.assert_equal(cell.cell_type, u'raw') | |||
|
31 | nt.assert_equal(cell.source, '') | |||
|
32 | ||||
|
33 | def test_raw_cell(): | |||
|
34 | cell = new_raw_cell('hi') | |||
|
35 | nt.assert_equal(cell.source, u'hi') | |||
|
36 | ||||
|
37 | def test_empty_code_cell(): | |||
|
38 | cell = new_code_cell('hi') | |||
|
39 | nt.assert_equal(cell.cell_type, 'code') | |||
|
40 | nt.assert_equal(cell.source, u'hi') | |||
|
41 | ||||
|
42 | def test_empty_display_data(): | |||
|
43 | output = new_output('display_data') | |||
|
44 | nt.assert_equal(output.output_type, 'display_data') | |||
|
45 | ||||
|
46 | def test_empty_stream(): | |||
|
47 | output = new_output('stream') | |||
|
48 | nt.assert_equal(output.output_type, 'stream') | |||
|
49 | nt.assert_equal(output.name, 'stdout') | |||
|
50 | nt.assert_equal(output.text, '') | |||
|
51 | ||||
|
52 | def test_empty_execute_result(): | |||
|
53 | output = new_output('execute_result', execution_count=1) | |||
|
54 | nt.assert_equal(output.output_type, 'execute_result') | |||
|
55 | ||||
|
56 | mimebundle = { | |||
|
57 | 'text/plain': "some text", | |||
|
58 | "application/json": { | |||
|
59 | "key": "value" | |||
|
60 | }, | |||
|
61 | "image/svg+xml": 'ABCDEF', | |||
|
62 | "application/octet-stream": 'ABC-123', | |||
|
63 | "application/vnd.foo+bar": "Some other stuff", | |||
|
64 | } | |||
|
65 | ||||
|
66 | def test_display_data(): | |||
|
67 | output = new_output('display_data', mimebundle) | |||
|
68 | for key, expected in mimebundle.items(): | |||
|
69 | nt.assert_equal(output.data[key], expected) | |||
|
70 | ||||
|
71 | def test_execute_result(): | |||
|
72 | output = new_output('execute_result', mimebundle, execution_count=10) | |||
|
73 | nt.assert_equal(output.execution_count, 10) | |||
|
74 | for key, expected in mimebundle.items(): | |||
|
75 | nt.assert_equal(output.data[key], expected) | |||
|
76 | ||||
|
77 | def test_error(): | |||
|
78 | o = new_output(output_type=u'error', ename=u'NameError', | |||
|
79 | evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2'] | |||
|
80 | ) | |||
|
81 | nt.assert_equal(o.output_type, u'error') | |||
|
82 | nt.assert_equal(o.ename, u'NameError') | |||
|
83 | nt.assert_equal(o.evalue, u'Name not found') | |||
|
84 | nt.assert_equal(o.traceback, [u'frame 0', u'frame 1', u'frame 2']) | |||
|
85 | ||||
|
86 | def test_code_cell_with_outputs(): | |||
|
87 | cell = new_code_cell(execution_count=10, outputs=[ | |||
|
88 | new_output('display_data', mimebundle), | |||
|
89 | new_output('stream', text='hello'), | |||
|
90 | new_output('execute_result', mimebundle, execution_count=10), | |||
|
91 | ]) | |||
|
92 | nt.assert_equal(cell.execution_count, 10) | |||
|
93 | nt.assert_equal(len(cell.outputs), 3) | |||
|
94 | er = cell.outputs[-1] | |||
|
95 | nt.assert_equal(er.execution_count, 10) | |||
|
96 | nt.assert_equal(er['output_type'], 'execute_result') | |||
|
97 | ||||
|
98 | def test_stream(): | |||
|
99 | output = new_output('stream', name='stderr', text='hello there') | |||
|
100 | nt.assert_equal(output.name, 'stderr') | |||
|
101 | nt.assert_equal(output.text, 'hello there') |
@@ -0,0 +1,105 b'' | |||||
|
1 | """Tests for nbformat validation""" | |||
|
2 | ||||
|
3 | # Copyright (c) IPython Development Team. | |||
|
4 | # Distributed under the terms of the Modified BSD License. | |||
|
5 | ||||
|
6 | import io | |||
|
7 | import os | |||
|
8 | ||||
|
9 | import nose.tools as nt | |||
|
10 | ||||
|
11 | from IPython.nbformat.validator import validate, ValidationError | |||
|
12 | from ..nbjson import reads | |||
|
13 | from ..nbbase import ( | |||
|
14 | nbformat, | |||
|
15 | new_code_cell, new_markdown_cell, new_notebook, | |||
|
16 | new_output, new_raw_cell, | |||
|
17 | ) | |||
|
18 | ||||
|
19 | def validate4(obj, ref=None): | |||
|
20 | return validate(obj, ref, version=nbformat) | |||
|
21 | ||||
|
22 | def test_valid_code_cell(): | |||
|
23 | cell = new_code_cell() | |||
|
24 | validate4(cell, 'code_cell') | |||
|
25 | ||||
|
26 | def test_invalid_code_cell(): | |||
|
27 | cell = new_code_cell() | |||
|
28 | ||||
|
29 | cell['source'] = 5 | |||
|
30 | with nt.assert_raises(ValidationError): | |||
|
31 | validate4(cell, 'code_cell') | |||
|
32 | ||||
|
33 | cell = new_code_cell() | |||
|
34 | del cell['metadata'] | |||
|
35 | ||||
|
36 | with nt.assert_raises(ValidationError): | |||
|
37 | validate4(cell, 'code_cell') | |||
|
38 | ||||
|
39 | cell = new_code_cell() | |||
|
40 | del cell['source'] | |||
|
41 | ||||
|
42 | with nt.assert_raises(ValidationError): | |||
|
43 | validate4(cell, 'code_cell') | |||
|
44 | ||||
|
45 | cell = new_code_cell() | |||
|
46 | del cell['cell_type'] | |||
|
47 | ||||
|
48 | with nt.assert_raises(ValidationError): | |||
|
49 | validate4(cell, 'code_cell') | |||
|
50 | ||||
|
51 | def test_invalid_markdown_cell(): | |||
|
52 | cell = new_markdown_cell() | |||
|
53 | ||||
|
54 | cell['source'] = 5 | |||
|
55 | with nt.assert_raises(ValidationError): | |||
|
56 | validate4(cell, 'markdown_cell') | |||
|
57 | ||||
|
58 | cell = new_markdown_cell() | |||
|
59 | del cell['metadata'] | |||
|
60 | ||||
|
61 | with nt.assert_raises(ValidationError): | |||
|
62 | validate4(cell, 'markdown_cell') | |||
|
63 | ||||
|
64 | cell = new_markdown_cell() | |||
|
65 | del cell['source'] | |||
|
66 | ||||
|
67 | with nt.assert_raises(ValidationError): | |||
|
68 | validate4(cell, 'markdown_cell') | |||
|
69 | ||||
|
70 | cell = new_markdown_cell() | |||
|
71 | del cell['cell_type'] | |||
|
72 | ||||
|
73 | with nt.assert_raises(ValidationError): | |||
|
74 | validate4(cell, 'markdown_cell') | |||
|
75 | ||||
|
76 | def test_invalid_raw_cell(): | |||
|
77 | cell = new_raw_cell() | |||
|
78 | ||||
|
79 | cell['source'] = 5 | |||
|
80 | with nt.assert_raises(ValidationError): | |||
|
81 | validate4(cell, 'raw_cell') | |||
|
82 | ||||
|
83 | cell = new_raw_cell() | |||
|
84 | del cell['metadata'] | |||
|
85 | ||||
|
86 | with nt.assert_raises(ValidationError): | |||
|
87 | validate4(cell, 'raw_cell') | |||
|
88 | ||||
|
89 | cell = new_raw_cell() | |||
|
90 | del cell['source'] | |||
|
91 | ||||
|
92 | with nt.assert_raises(ValidationError): | |||
|
93 | validate4(cell, 'raw_cell') | |||
|
94 | ||||
|
95 | cell = new_raw_cell() | |||
|
96 | del cell['cell_type'] | |||
|
97 | ||||
|
98 | with nt.assert_raises(ValidationError): | |||
|
99 | validate4(cell, 'raw_cell') | |||
|
100 | ||||
|
101 | def test_sample_notebook(): | |||
|
102 | here = os.path.dirname(__file__) | |||
|
103 | with io.open(os.path.join(here, os.pardir, os.pardir, 'tests', "test4.ipynb"), encoding='utf-8') as f: | |||
|
104 | nb = reads(f.read()) | |||
|
105 | validate4(nb) |
General Comments 0
You need to be logged in to leave comments.
Login now