Skip to content

Commit

Permalink
Merge pull request #480 from poke1024/imathics-new
Browse files Browse the repository at this point in the history
Changes for imathics kernel
  • Loading branch information
sn6uv authored Aug 22, 2016
2 parents 76e1fc5 + 73fc501 commit faf14d7
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 33 deletions.
22 changes: 14 additions & 8 deletions mathics/builtin/graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from math import floor, ceil, log10
import json
import base64
from six.moves import map
from six.moves import range
from six.moves import zip
Expand Down Expand Up @@ -1453,14 +1454,19 @@ def boxes_to_xml(self, leaves, **options):
w += 2
h += 2

xml = (
'<svg xmlns:svg="http://www.w3.org/2000/svg" '
'xmlns="http://www.w3.org/2000/svg"\nversion="1.0" width="%f" '
'height="%f" viewBox="%f %f %f %f">%s</svg>') % (
width, height, xmin, ymin, w, h, svg)

xml = """<mtable><mtr><mtd>%s</mtd></mtr></mtable>""" % xml
return xml
svg_xml = '''
<svg xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
viewBox="%s">
%s
</svg>
''' % (' '.join('%f' % t for t in (xmin, ymin, w, h)), svg)

return '<mglyph width="%dpx" height="%dpx" src="data:image/svg+xml;base64,%s"/>' % (
int(width),
int(height),
base64.b64encode(svg_xml.encode('utf8')).decode('utf8'))

def axis_ticks(self, xmin, xmax):
def round_to_zero(value):
Expand Down
3 changes: 1 addition & 2 deletions mathics/builtin/inout.py
Original file line number Diff line number Diff line change
Expand Up @@ -1732,8 +1732,7 @@ class MathMLForm(Builtin):
= <math><mi>\u03bc</mi></math>
#> MathMLForm[Graphics[Text["\u03bc"]]]
= <math><mtable><mtr><mtd><svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
. version="1.0" width="..." height="..." viewBox="..."><foreignObject x="..." y="..." ox="0.000000" oy="0.000000" style="stroke: none; fill: none; color: rgb(0.000000%, 0.000000%, 0.000000%)"><math><mtext>\u03bc</mtext></math></foreignObject></svg></mtd></mtr></mtable></math>
= <math><mglyph width="..." height="..." src="data:image/svg+xml;base64,..."/></math>
## The <mo> should contain U+2062 INVISIBLE TIMES
#> MathMLForm[MatrixForm[{{2*a, 0},{0,0}}]]
Expand Down
54 changes: 37 additions & 17 deletions mathics/core/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,23 @@ def get_data(self):
}


class Output(object):
def max_stored_size(self, settings):
return settings.MAX_STORED_SIZE

def out(self, out):
pass

def clear(self, wait):
raise NotImplementedError

def display(self, data, metadata):
raise NotImplementedError


class Evaluation(object):
def __init__(self, definitions=None,
out_callback=None, format='text', catch_interrupt=True):
output=None, format='text', catch_interrupt=True):
from mathics.core.definitions import Definitions

if definitions is None:
Expand All @@ -156,7 +170,7 @@ def __init__(self, definitions=None,
self.timeout = False
self.stopped = False
self.out = []
self.out_callback = out_callback
self.output = output if output else Output()
self.listeners = {}
self.options = None
self.predetermined_out = None
Expand Down Expand Up @@ -221,7 +235,7 @@ def evaluate():
self.definitions.add_rule('Out', Rule(
Expression('Out', line_no), stored_result))
if result != Symbol('Null'):
return self.format_output(result)
return self.format_output(result, self.format)
else:
return None
try:
Expand Down Expand Up @@ -261,7 +275,7 @@ def evaluate():
if exc_result is not None:
self.recursion_depth = 0
if exc_result != Symbol('Null'):
result = self.format_output(exc_result)
result = self.format_output(exc_result, self.format)

result = Result(self.out, result, line_no)
self.out = []
Expand All @@ -288,23 +302,31 @@ def get_stored_result(self, result):

# Prevent too large results from being stored, as this can exceed the
# DB's max_allowed_packet size
data = pickle.dumps(result)
if len(data) > 10000:
return Symbol('Null')
max_stored_size = self.output.max_stored_size(settings)
if max_stored_size is not None:
data = pickle.dumps(result)
if len(data) > max_stored_size:
return Symbol('Null')
return result

def stop(self):
self.stopped = True

def format_output(self, expr):
def format_output(self, expr, format=None):
if format is None:
format = self.format

if isinstance(format, dict):
return dict((k, self.format_output(expr, f)) for k, f in format.items())

from mathics.core.expression import Expression, BoxError

if self.format == 'text':
if format == 'text':
result = expr.format(self, 'System`OutputForm')
elif self.format == 'xml':
elif format == 'xml':
result = Expression(
'StandardForm', expr).format(self, 'System`MathMLForm')
elif self.format == 'tex':
elif format == 'tex':
result = Expression('StandardForm', expr).format(
self, 'System`TeXForm')
else:
Expand Down Expand Up @@ -368,20 +390,18 @@ def message(self, symbol, tag, *args):
text = String("Message %s::%s not found." % (symbol_shortname, tag))

text = self.format_output(Expression(
'StringForm', text, *(from_python(arg) for arg in args)))
'StringForm', text, *(from_python(arg) for arg in args)), 'text')

self.out.append(Message(symbol_shortname, tag, text))
if self.out_callback:
self.out_callback(self.out[-1])
self.output.out(self.out[-1])

def print_out(self, text):
from mathics.core.expression import from_python

text = self.format_output(from_python(text))
text = self.format_output(from_python(text), 'text')

self.out.append(Print(text))
if self.out_callback:
self.out_callback(self.out[-1])
self.output.out(self.out[-1])
if settings.DEBUG_PRINT:
print('OUT: ' + text)

Expand Down
17 changes: 13 additions & 4 deletions mathics/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from mathics.core.definitions import Definitions
from mathics.core.expression import strip_context
from mathics.core.evaluation import Evaluation
from mathics.core.evaluation import Evaluation, Output
from mathics.core.parser import LineFeeder, FileLineFeeder
from mathics import version_string, license_string, __version__
from mathics import settings
Expand Down Expand Up @@ -176,6 +176,14 @@ def empty(self):
return False


class TerminalOutput(Output):
def __init__(self, shell):
self.shell = shell

def out(self, out):
return self.shell.out_callback(out)


def main():
argparser = argparse.ArgumentParser(
prog='mathics',
Expand Down Expand Up @@ -238,7 +246,7 @@ def main():
if args.execute:
for expr in args.execute:
print(shell.get_in_prompt() + expr)
evaluation = Evaluation(shell.definitions, out_callback=shell.out_callback)
evaluation = Evaluation(shell.definitions, output=TerminalOutput(shell))
result = evaluation.parse_evaluate(expr, timeout=settings.TIMEOUT)
shell.print_result(result)

Expand All @@ -249,7 +257,8 @@ def main():
feeder = FileLineFeeder(args.FILE)
try:
while not feeder.empty():
evaluation = Evaluation(shell.definitions, out_callback=shell.out_callback, catch_interrupt=False)
evaluation = Evaluation(
shell.definitions, output=TerminalOutput(shell), catch_interrupt=False)
query = evaluation.parse_feeder(feeder)
if query is None:
continue
Expand All @@ -270,7 +279,7 @@ def main():

while True:
try:
evaluation = Evaluation(shell.definitions, out_callback=shell.out_callback)
evaluation = Evaluation(shell.definitions, output=TerminalOutput(shell))
query = evaluation.parse_feeder(shell)
if query is None:
continue
Expand Down
4 changes: 4 additions & 0 deletions mathics/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@

MAX_RECURSION_DEPTH = 512

# max pickle.dumps() size for storing results in DB
# historically 10000 was used on public mathics servers
MAX_STORED_SIZE = 10000

ADMINS = (
('Admin', '[email protected]'),
)
Expand Down
28 changes: 28 additions & 0 deletions mathics/web/media/js/mathics.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,10 +274,38 @@ function translateDOMElement(element, svg) {
return dom;
}

function convertMathGlyphs(dom) {
// convert mglyphs to their classic representation (<svg> or <img>), so the new mglyph logic does not make
// anything worse in the classic Mathics frontend for now. In the long run, this code should vanish.

var MML = "http://www.w3.org/1998/Math/MathML";
var glyphs = dom.getElementsByTagName("mglyph");
for (var i = 0; i < glyphs.length; i++) {
var glyph = glyphs[i];
var src = glyph.getAttribute('src');
if (src.startsWith('data:image/svg+xml;base64,')) {
var svgText = atob(src.substring(src.indexOf(",") + 1));
var mtable =document.createElementNS(MML, "mtable");
mtable.innerHTML = '<mtr><mtd>' + svgText + '</mtd></mtr>';
var svg = mtable.getElementsByTagNameNS("*", "svg")[0];
svg.setAttribute('width', glyph.getAttribute('width'));
svg.setAttribute('height', glyph.getAttribute('height'));
glyph.parentNode.replaceChild(mtable, glyph);
} else if (src.startsWith('data:image/')) {
var img = document.createElement('img');
img.setAttribute('src', src)
img.setAttribute('width', glyph.getAttribute('width'));
img.setAttribute('height', glyph.getAttribute('height'));
glyph.parentNode.replaceChild(img, glyph);
}
}
}

function createLine(value) {
if (value.startsWith('<math')) {
var dom = document.createElement('div');
dom.updateDOM(value);
convertMathGlyphs(dom);
return translateDOMElement(dom.childNodes[0]);
} else {
var lines = value.split('\n');
Expand Down
9 changes: 7 additions & 2 deletions mathics/web/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@
from django.contrib.auth.models import User

from mathics.core.definitions import Definitions
from mathics.core.evaluation import Evaluation, Message, Result
from mathics.core.evaluation import Evaluation, Message, Result, Output

from mathics.web.models import Query, Worksheet
from mathics.web.forms import LoginForm, SaveForm
from mathics.doc import documentation
from mathics.doc.doc import DocPart, DocChapter, DocSection
import six
from six.moves import range
from string import Template

if settings.DEBUG:
JSON_CONTENT_TYPE = 'text/html'
Expand All @@ -44,6 +45,10 @@ def __init__(self, result={}):
super(JsonResponse, self).__init__(response, content_type=JSON_CONTENT_TYPE)


class WebOutput(Output):
pass


def require_ajax_login(func):
def new_func(request, *args, **kwargs):
if not request.user.is_authenticated():
Expand Down Expand Up @@ -102,7 +107,7 @@ def query(request):

user_definitions = request.session.get('definitions')
definitions.set_user_definitions(user_definitions)
evaluation = Evaluation(definitions, format='xml')
evaluation = Evaluation(definitions, format='xml', output=WebOutput())
feeder = MultiLineFeeder(input, '<notebook>')
results = []
try:
Expand Down

0 comments on commit faf14d7

Please sign in to comment.