Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
| Download
Views: 39604
1
#!/usr/bin/env python
2
# -*- coding: utf8 -*-
3
4
# CoCalc: Collaborative Calculation in the Cloud
5
#
6
# Copyright (C) 2017, 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 a .m GNU Octave file to an SMC sagews file.
25
It relies on the sagews built-in mode `%octave` to instantiate a communication bridge
26
to the octave Jupyter kernel.
27
28
Authors:
29
* Harald Schilly <[email protected]>, started June 2016
30
"""
31
32
from __future__ import print_function
33
import json
34
from ansi2html import Ansi2HTMLConverter
35
36
from smc_pyutil.sws2sagews import MARKERS, uuid
37
38
class SagewsCell(object):
39
40
'''
41
Create unicode string corresponding to cell in a sage worksheet, including input/output
42
marker and uuid.
43
'''
44
45
def __init__(self, input='', outputs=None, md=None):
46
'''
47
Either specify `md` as markdown text, which is used for the text boxes in ipynb,
48
or specify `outputs` as the list of output data dictionaries from ipynb (format version 4)
49
'''
50
if outputs is not None and md is not None:
51
raise ArgumentError('Either specify md or outputs -- not both!')
52
# inline: only the essential html, no header with styling, etc.
53
# linkify: detects URLs
54
self._ansi2htmlconv = Ansi2HTMLConverter(inline=True, linkify=True)
55
# input data
56
self.input = input or ''
57
# cell states data
58
self.md = md or ''
59
self.html = ''
60
self.output = ''
61
self.ascii = ''
62
self.error = ''
63
self.stdout = ''
64
# process outputs list
65
if outputs is not None:
66
self.process_outputs(outputs)
67
68
def ansi2htmlconv(self, ansi):
69
'''
70
Sometimes, ipynb contains ansi strings with control characters for colors.
71
This little helper converts this to fixed-width formatted html with coloring.
72
'''
73
# `full = False` or else cell output is huge
74
html = self._ansi2htmlconv.convert(ansi, full=False)
75
return '<pre><span style="font-family:monospace;">%s</span></pre>' % html
76
77
def process_outputs(self, outputs):
78
"""
79
Each cell has one or more outputs of different types.
80
They are collected by type and transformed later.
81
"""
82
stdout = []
83
html = []
84
# ascii: for actual html content, that has been converted from ansi-encoded ascii
85
ascii = []
86
# errors are similar to ascii content
87
errors = []
88
89
for output in outputs:
90
ot = output['output_type']
91
if ot == 'stream':
92
ascii.append(self.ansi2htmlconv(output['text']))
93
94
elif ot in ['display_data', 'execute_result']:
95
data = output['data']
96
if 'text/html' in data:
97
html.append(data['text/html'])
98
if 'text/latex' in data:
99
html.append(data['text/latex'])
100
if 'text/plain' in data:
101
stdout.append(data['text/plain'])
102
# print(json.dumps(data, indent=2))
103
104
elif ot in 'error':
105
if 'traceback' in output:
106
# print(json.dumps(output['traceback'], indent=2))
107
for tr in output['traceback']:
108
errors.append(self.ansi2htmlconv(tr))
109
110
else:
111
print("ERROR: unknown output type '%s':\n%s" %
112
(ot, json.dumps(output, indent=2)))
113
114
self.stdout = u'\n'.join(stdout)
115
self.html = u'<br/>'.join(html)
116
self.error = u'<br/>'.join(errors)
117
self.ascii = u'<br/>'.join(ascii)
118
119
def convert(self):
120
cell = None
121
html = self.html.strip()
122
input = self.input.strip()
123
stdout = self.stdout.strip()
124
ascii = self.ascii.strip()
125
error = self.error.strip()
126
md = self.md.strip()
127
128
def mkcell(input='', output='', type='stdout', modes=''):
129
'''
130
This is a generalized template for creating a single sagews cell.
131
132
- sagews modes:
133
* '%auto' → 'a'
134
* '%hide' → 'i'
135
* '%hideall' → 'o'
136
137
- type:
138
* err/ascii: html formatted error or ascii/ansi content
139
* stdout: plain text
140
* html/md: explicit input of html code or md, as display_data
141
'''
142
cell = MARKERS['cell'] + uuid() + modes + MARKERS['cell'] + u'\n'
143
if type == 'md':
144
cell += '%%%s\n' % type
145
output = input
146
cell += input
147
# input is done, now the output part
148
if type in ['err', 'ascii']:
149
# mangle type of output to html
150
type = 'html'
151
cell += (u'\n' + MARKERS['output'] + uuid() + MARKERS['output'] +
152
json.dumps({type: output, 'done': True}) + MARKERS['output']) + u'\n'
153
return cell
154
155
# depending on the typed arguments, construct the sagews cell
156
if html:
157
cell = mkcell(input=input, output = html, type='html', modes='')
158
elif md:
159
cell = mkcell(input=md, type = 'md', modes='i')
160
elif error:
161
cell = mkcell(input=input, output=error, type='err')
162
elif ascii:
163
cell = mkcell(input=input, output=ascii, type='ascii')
164
165
if cell is None and (input or stdout):
166
cell = mkcell(input, stdout)
167
168
return cell
169
170