Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ipython notebook page #32

Open
wants to merge 55 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
a44c334
Databases can be used to store result though i have avoided it.
sahilshekhawat Feb 7, 2014
0852c97
it is encoding the result so that they can be included in url as GET …
sahilshekhawat Feb 7, 2014
ae04c42
initial commit for submodules.
sahilshekhawat Feb 7, 2014
9c1fcb5
views to create the json of ipython notebook
sahilshekhawat Feb 7, 2014
e52d466
Template to render the json of ipython notebook
sahilshekhawat Feb 7, 2014
d555bcf
Added url of ipython notebook's json which is access by nbviewer
sahilshekhawat Feb 7, 2014
94b7dd2
added links to json and notebook rendered on nbviewer.
sahilshekhawat Feb 7, 2014
8108849
initial commit after commiting in submodules docutils/
sahilshekhawat Feb 7, 2014
f420b2b
NO changes Done.They are still the original models.
sahilshekhawat Feb 10, 2014
9582e54
Views of the json of the IPython notebook
sahilshekhawat Feb 10, 2014
dbfff8c
Added the feature to encode the url of the json.
sahilshekhawat Feb 10, 2014
012f815
Added links to IPython notebook's page in nbviewer
sahilshekhawat Feb 10, 2014
081f7a5
Json's Template to render the IPython notebook json.
sahilshekhawat Feb 10, 2014
896b83e
Added the link to IPython Notebook page.
sahilshekhawat Feb 11, 2014
375150d
removed trailing whitespaces
sahilshekhawat Feb 15, 2014
150e6b8
removed blank lines
sahilshekhawat Feb 15, 2014
5a1f1f1
removed extra vacant lines.
sahilshekhawat Feb 15, 2014
a2b8c1f
changed the GET parameter from result to input.
sahilshekhawat Feb 15, 2014
20bd62d
encoding input taken from user than the calculated result.
sahilshekhawat Feb 15, 2014
c09aa44
changed the GET parameter.
sahilshekhawat Feb 15, 2014
c149864
Added recalculation by SymPyGamma by taking input.
sahilshekhawat Feb 15, 2014
4c33bd7
passing input into url without encoding.
sahilshekhawat Feb 15, 2014
e7d77e5
Corrected the links and fixed the errors.
sahilshekhawat Feb 15, 2014
7cac6a4
Deleted the unused TEst Variable.
sahilshekhawat Feb 15, 2014
68f5862
removed the script tag
sahilshekhawat Feb 15, 2014
4d5db5d
Added $$ and removed script tags from the mathjax.
sahilshekhawat Feb 15, 2014
ff8b1f6
Added '$$' to mathjax
sahilshekhawat Feb 15, 2014
7caed87
removed extra white spaces.
sahilshekhawat Feb 16, 2014
9f1d58c
removed all the extra imports
sahilshekhawat Feb 16, 2014
0db6c2c
added links to nbviewer and json.
sahilshekhawat Feb 16, 2014
fcae135
removes blank lines.
sahilshekhawat Feb 17, 2014
61d1d0f
removed unused import of string.
sahilshekhawat Feb 17, 2014
fd1f422
rebased the previous commit.
sahilshekhawat Feb 17, 2014
fc5b10f
removed import of urllib
sahilshekhawat Feb 17, 2014
54bc84d
Merge branch 'master' of https://github.com/sympy/sympy_gamma into ip…
sahilshekhawat Mar 22, 2014
fae9d1a
Fixed the problem which was occuring while rendering in the browser
Apr 16, 2014
b092da1
Changed the name of the file to make it easily identifiable
Apr 16, 2014
f158fd5
Added cards to be converted into json
sahilshekhawat May 26, 2014
f824ba7
changed json's url from 'result.ipynb' to 'result'
sahilshekhawat May 26, 2014
08e5ae5
deleted result_notebook.ipynb file
sahilshekhawat May 26, 2014
d2e5abb
fixed bug
sahilshekhawat May 26, 2014
5e9a201
started using SympyGamma to get cards
sahilshekhawat May 26, 2014
059f3e7
changed noetbook's url to 'export_notebook'
sahilshekhawat May 26, 2014
453439a
quoting and unquoting input to prevent space errors
sahilshekhawat May 26, 2014
ed32069
fixed bug 'i'
sahilshekhawat May 26, 2014
86c8edc
Added the codes to code cell in ipython notebook
sahilshekhawat Jun 5, 2014
5a73388
Added codes to codecell of ipython notebook and did styling
sahilshekhawat Jun 9, 2014
d82ddd2
added traceback to the output of errored cells
sahilshekhawat Jun 9, 2014
1efc0ac
removed extra lines used for testing, cleaned the code
sahilshekhawat Jun 9, 2014
78388ec
Merge branch 'master' of https://github.com/sympy/sympy_gamma into ip…
sahilshekhawat Jun 9, 2014
adcb811
Fixed some minor issues
sahilshekhawat Jun 9, 2014
e26cdb9
Fixed issues related to formatting
sahilshekhawat Jun 10, 2014
8c04f10
Fixed issues related to formatting
sahilshekhawat Jun 10, 2014
a48d6b6
removed redundant tags
sahilshekhawat Jun 10, 2014
d5cfce1
Added 'learn more' block
sahilshekhawat Jun 12, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 195 additions & 0 deletions app/notebook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
from __future__ import absolute_import
from django.http import HttpResponse
from copy import copy
from app.logic.logic import SymPyGamma
from app.views import eval_card
from HTMLParser import HTMLParser
import json
import urllib2
import traceback

#styling for notebook
styling = '''<style>
li{ list-style-type:none;
list-style-position:inside;
margin:0;
padding:0;}
</style>'''

class Parser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.cell_input = []
self.is_cell_input = False
def handle_starttag(self, tag, attrs):
self.is_cell_input = False
if tag == 'div':
for attribute, value in attrs:
if attribute=='class' and value=='cell_input':
self.is_cell_input = True
def handle_data(self, data):
if self.is_cell_input:
self.cell_input.append(data)

def result_json(request):

''' IPython notebook format generator. Parses the result set and
converts them into IPython notebook's format. '''

notebook_format = { "metadata": {"name": ""}, "nbformat": 3, "nbformat_minor": 0, "worksheets": [{ "cells": [],"metadata": {} }]}
code_cell = {"cell_type": "code", "input": [], "language": "python", "metadata": {}, "outputs": [{ "output_type": "pyout", "text": [], "prompt_number": 1}], "prompt_number": 1 },
markdown_cell = {"cell_type": "markdown","metadata": {},"source":[]},
heading_cell = {"cell_type": "heading","level": 3,"metadata": {},"source": []},

exp = request.GET.get('i')
exp = urllib2.unquote(exp)
g = SymPyGamma()
result = g.eval(exp)
notebook = copy(notebook_format)

prompt_number = 1 #initial value

for cell in result:
title = copy(heading_cell[0])
title['level'] = 3
a = str(cell['title'])
title['source'] = [a]
notebook['worksheets'][0]['cells'].append(title)

if 'input' in cell:
if cell['input'] != None and cell['input'] != '':
inputs = copy(code_cell[0])
inputs['input'] = [ str(cell['input']) ]
inputs['prompt_number'] = prompt_number
prompt_number = prompt_number + 1
notebook['worksheets'][0]['cells'].append(inputs)

if 'output' in cell:
output = copy(markdown_cell[0])

if 'pre_output' in cell:
if cell['pre_output'] !="" and cell['pre_output'] != 'None':
pre_output = copy(markdown_cell[0])
pre_output['source'] = ['$$'+str(cell['pre_output'])+'=$$']
notebook['worksheets'][0]['cells'].append(pre_output)

if cell['output'] != "" and 'script' in cell['output']:
output['source'] = [cell['output']]
notebook['worksheets'][0]['cells'].append(output)
elif 'div' in cell['output']:
output['source'] = [cell['output']]
notebook['worksheets'][0]['cells'].append(output)

if 'card' in cell:
if cell['card'] != 'plot':
card_name = cell['card']
variable = cell['var']
parameters = {}
if 'pre_output' in cell:
if cell['pre_output'] != '' and cell['pre_output'] != 'None':
cell_pre_output = copy(markdown_cell[0])
cell_pre_output['source'] = ['$$'+str(cell['pre_output'])+ '=$$']
notebook['worksheets'][0]['cells'].append(cell_pre_output)

try:
card_json = g.eval_card(card_name, exp, variable, parameters)
card_json_output = card_json['output']

parser = Parser()
parser.feed(card_json_output)
parsed_cell_inputs = parser.cell_input #list of data values with <div class='cell_input'>
card_json_output = [card_json_output]

for card_cell_input in parsed_cell_inputs:
if card_cell_input != '\n' and card_cell_input != '</div>' and card_cell_input != '\\':

card_json_output = card_json_output[0].split(card_cell_input)
try: #removing <ul>'s, <li>'s and <div>'s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be better of with a regex or with an actual HTML parser. If the output ever changes, this would break.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am already using an htmlparser (see top) and i think "replace" should do the trick, also I dont want to increase the complexity of the code. I know its silly to discuss these little points, but am I right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I'm trying to determine the intent of this section of code. It is trying to extract the input and output sections from a multiple-result card, correct? I think there are better ways to handle this. See https://gist.github.com/lidavidm/37a0a27582805872334d - it just uses the HTML parser and extracts both the input expression and output LaTeX.

if card_json_output[0][:7] == '</div>\n':
card_json_output[0] = card_json_output[0][7:]
if card_json_output[0][:7] == '\n</div>':
card_json_output[0] = card_json_output[0][7:]
if card_json_output[0][:10] == '<ul>\n<li>\n':
card_json_output[0] = card_json_output[0][10:]
if card_json_output[0][:9] == '<ul>\n<li>':
card_json_output[0] = card_json_output[0][19:]
if card_json_output[0][-24:] == '<div class=\"cell_input\">':
card_json_output[0] = card_json_output[0][:-24]
if card_json_output[0][-12:] == '\n</li>\n<li>\n':
card_json_output[0] = card_json_output[0][:-12]
if card_json_output[0][-11:] == '</li>\n<li>\n':
card_json_output[0] = card_json_output[0][:-11]
except:
pass
card_result = copy(markdown_cell[0])
card_result['source'] = [card_json_output[0]]
notebook['worksheets'][0]['cells'].append(card_result) #storing output after input

if card_cell_input[:1] == '\n':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two conditionals can just be replaced with card_cell_input.strip().

card_cell_input = card_cell_input[1:]
if card_cell_input[-1:] == '\n':
card_cell_input = card_cell_input[:-1]

card_heading = copy(code_cell[0])
card_heading['input'] = [card_cell_input]
card_heading['prompt_number'] = prompt_number
prompt_number = prompt_number + 1
notebook['worksheets'][0]['cells'].append(card_heading)

if len(card_json_output) > 1 :
card_json_output = [card_json_output[1]]
else:
card_json_output = [card_json_output[0]]

if card_json_output[0] != '<':
try:
if card_json_output[0][:7] == '</div>\n':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this would be more robust with either regex or an actual HTML parser.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget that you can't parse HTML with regex.

card_json_output[0] = card_json_output[0][7:]
if card_json_output[0][:10] == '<ul>\n<li>':
card_json_output[0] = card_json_output[0][10:]
if card_json_output[0][:9] == '<ul>\n<li>':
card_json_output[0] = card_json_output[0][9:]
if card_json_output[0][-12:] == '\n</li>\n</ul>':
card_json_output[0] = card_json_output[0][:-12]
if card_json_output[0][-11:] == '</li>\n</ul>':
card_json_output[0] = card_json_output[0][:-11]


except:
pass
card_last_result = copy(markdown_cell[0])
card_last_result['source'] = [card_json_output[0]]
notebook['worksheets'][0]['cells'].append(card_last_result)
except:
card_error = copy(markdown_cell[0])
card_error['source'] = [traceback.format_exc(1)]
notebook['worksheets'][0]['cells'].append(card_error)
else:
card_plot = copy(markdown_cell[0])
card_plot['source'] = ['Plotting is not yet implemented.']
notebook['worksheets'][0]['cells'].append(card_plot)

if 'cell_output' in cell:
if cell['cell_output'] != "":
cell_output = copy(markdown_cell[0])
cell_output['source'] = [cell['cell_output']]
notebook['worksheets'][0]['cells'].append(cell_output)

if 'error' in cell:
cell_error = copy(markdown_cell[0])
cell_error['source'] = [cell['error']]
notebook['worksheets'][0]['cells'].append(cell_error)

else:
pass

#styling for the notebook (Css)
notebook_styling = copy(markdown_cell[0])
notebook_styling['source'] = [styling]
notebook['worksheets'][0]['cells'].append(notebook_styling)
#Converting it into the json format.
notebook_json = json.dumps(notebook)
response = HttpResponse(notebook_json, content_type = 'text/plain')
#uncomment the following line to display json rather than downloading it.
response['Content-Disposition'] = 'attachment; filename=gamma.ipynb'
return response
8 changes: 5 additions & 3 deletions app/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import datetime
import traceback


LIVE_URL = '<a href="http://live.sympy.org">SymPy Live</a>'
LIVE_PROMOTION_MESSAGES = [
'Need more control? Try ' + LIVE_URL + '.',
Expand Down Expand Up @@ -199,7 +200,8 @@ def input(request, user):
form = SearchForm(request.GET)
if form.is_valid():
input = form.cleaned_data["i"]

export_notebook = urllib2.quote(str(input))
encoded_export_notebook = urllib2.quote(str(export_notebook)) #encoding twice for nbviewer.
if input.strip().lower() in ('random', 'example', 'random example'):
return redirect('/random')

Expand All @@ -221,11 +223,11 @@ def input(request, user):
elif not models.Query.query(models.Query.text==input).get():
query = models.Query(text=input, user_id=None)
query.put()


# For some reason the |random tag always returns the same result
return ("result.html", {
"input": input,
"encoded_export_notebook": encoded_export_notebook,
"export_notebook": export_notebook,
"result": r,
"form": form,
"MEDIA_URL": settings.MEDIA_URL,
Expand Down
10 changes: 8 additions & 2 deletions templates/result.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@ <h1><a href="/">
{{ form.i }}<input class="input_field" type="submit" value="=" />
</form>
</div>

<div class="result">
{% for cell in result %}
{% show_card cell input %}
{% endfor %}
<div class="foot">
See what <a class="wolfram"
<p>See what <a class="wolfram"
href="http://www.wolframalpha.com/input/?i={{input|urlencode}}">
Wolfram|Alpha</a> has to say.
Wolfram|Alpha</a> has to say.</p>
<p>See the results as IPython <a class="notebook"
href="http://nbviewer.ipython.org/url/sympygamma.com/export_notebook//%3Fi%3D{{ encoded_export_notebook }}">
Notebook Viewer</a> or export to an IPython Notebook <a href="{% url app.notebook.result_json %}?i={{ export_notebook }}">file</a></p>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would word this as "See these results in IPython Notebook Viewer or export to an IPython Notebook file.", just to make it clear which is which.


<p>{{ promote_live|safe }}</p>
</div>
</div>
Expand Down
3 changes: 1 addition & 2 deletions urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@
# Example:
# (r'^notebook/', include('notebook.foo.urls')),
(r'^$', 'app.views.index'),

(r'^export_notebook/$', 'app.notebook.result_json'),
(r'^input/', 'app.views.input'),
(r'^about/$', 'app.views.about'),
(r'^random', 'app.views.random_example'),

(r'user/remove/(?P<qid>.*)$', 'app.views.remove_query'),

(r'card/(?P<card_name>\w*)$', 'app.views.eval_card'),
Expand Down