##// END OF EJS Templates
backport nbformat v4 to 2.x
MinRK -
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