Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 39558
1
#!/usr/bin/env python
2
# -*- coding: utf8 -*-
3
4
# CoCalc: Collaborative Calculation in the Cloud
5
#
6
# Copyright (C) 2016, SageMath, Inc.
7
#
8
# This program is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation, either version 3 of the License, or
11
# (at your option) any later version.
12
#
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
#
21
#
22
23
"""
24
This script converts an .ipynb jupyter notebook file to an SMC sagews file.
25
It relies on the sagews command `jupyter()` to instantiate the communication bridge
26
to the Jupyter kernel.
27
28
Authors:
29
30
* Harald Schilly <[email protected]>, started June 2016
31
"""
32
33
from __future__ import print_function
34
import sys
35
import os
36
import codecs
37
import textwrap
38
# reading the ipynb via http://nbformat.readthedocs.io/en/latest/api.html
39
import nbformat
40
41
from smc_pyutil.lib import SagewsCell
42
43
class Ipynb2SageWS(object):
44
45
def __init__(self, filename, overwrite=True):
46
"""
47
Convert a Jupyter Notebook .ipynb file to a CoCalc .sagews file.
48
49
INPUT:
50
- ``filename`` -- the name of an ipynb file, say foo.ipynb
51
52
OUTPUT:
53
- creates a file foo.sagews if it doesn't already exist
54
"""
55
self.infile = filename
56
base = os.path.splitext(filename)[0]
57
self.outfile = base + '.sagews'
58
if not overwrite and os.path.exists(self.outfile):
59
raise Exception(
60
"%s: Warning --CoCalc worksheet '%s' already exists. Not overwriting.\n" % (sys.argv[0], self.outfile))
61
62
self.nb = None # holds the notebook data
63
self.output = None # use self.write([line]) to write to output
64
65
def convert(self):
66
"""
67
Main routine
68
"""
69
self.read()
70
self.open()
71
self.kernel()
72
self.body()
73
74
def read(self):
75
"""
76
Reads the ipynb file, regardless of version, and converts to API version 4
77
"""
78
self.nb = nbformat.read(self.infile, 4)
79
80
def write(self, line):
81
if line is not None:
82
self.output.send(line)
83
84
def open(self):
85
sys.stdout.write("%s: Creating CoCalc worksheet '%s'\n" %
86
(sys.argv[0], self.outfile))
87
sys.stdout.flush()
88
89
def output():
90
with codecs.open(self.outfile, 'w', 'utf8') as fout:
91
while True:
92
cell = yield
93
if cell is None:
94
break
95
fout.write(cell)
96
self.output = output()
97
self.output.next()
98
99
def kernel(self):
100
"""
101
The first cell contains a small info text and defines the global jupyter mode,
102
based on the kernel name in the ipynb file!
103
"""
104
spec = self.nb['metadata']
105
name = spec['kernelspec']['name']
106
cell = '''\
107
%auto
108
# This cell automatically evaluates on startup -- or run it manually if it didn't evaluate.
109
# Here, it initializes the Jupyter kernel with the specified name and sets it as the default mode for this worksheet.
110
jupyter_kernel = jupyter("{}") # run "jupyter?" for more information.
111
%default_mode jupyter_kernel'''.format(name)
112
self.write(SagewsCell(input=textwrap.dedent(cell)).convert())
113
114
def body(self):
115
"""
116
Converting all cells of the ipynb as the body of the sagews document.
117
118
see http://nbformat.readthedocs.io/en/latest/format_description.html
119
"""
120
121
for cell in self.nb.cells:
122
ct = cell['cell_type']
123
source = cell.get('source', None)
124
outputs = cell.get('outputs', [])
125
126
if ct == 'markdown':
127
self.write(SagewsCell(md=source).convert())
128
129
elif ct == 'code':
130
self.write(SagewsCell(input=source, outputs=outputs).convert())
131
132
elif ct == 'raw':
133
self.write(SagewsCell(input=source).convert())
134
135
else:
136
print("ERROR: cell type '%s' not recognized:\n%s" %
137
(ct, json.dumps(cell, indent=2)))
138
139
140
def main():
141
if len(sys.argv) == 1:
142
sys.stderr.write("""
143
Convert a Jupyter Notebook .ipynb file to a CoCalc .sagews file.
144
145
Usage: %s path/to/filename.ipynb [path/to/filename2.ipynb ...]
146
147
Creates corresponding file path/to/filename.sagews, if it doesn't exist.
148
""" % sys.argv[0])
149
sys.exit(1)
150
151
for path in sys.argv[1:]:
152
Ipynb2SageWS(path).convert()
153
154
if __name__ == "__main__":
155
main()
156
157