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

Html notebook #179

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7fee9ed
First commit for basehttpserver -- mostly a copy from qtkernelmanager
jamesgao Oct 11, 2010
7100286
Earliest barebones dumping of the sub socket to http, will improve soon
jamesgao Oct 12, 2010
edd7029
Add logic to serve up normal files, useful for javascript files
jamesgao Oct 12, 2010
d18541a
xreq_channel now working with the http channel! Need to make sure tha…
Oct 12, 2010
9dce0dc
Probably best to not commit jquery... Let's link it from googlecode
Oct 12, 2010
d5a3490
Add some javascript to make terminal listing pretty, specifically, to…
jamesgao Oct 13, 2010
ddffe2b
Finally making better javascript tracking, looks more like ipython now
Oct 14, 2010
30d7333
Partially fix "fixConsole" function which was breaking on some outputs
jamesgao Oct 14, 2010
7fe119b
Fix the kernelmanager so that running it from arbitrary paths work
jamesgao Oct 15, 2010
3001fb5
Forgot to add basepath to the os.path.exists, otherwise it only sends
jamesgao Oct 15, 2010
8b70aad
Add support for inline svg dumping. Now pylab works!
Oct 15, 2010
6abdb49
Argh, that was a painful commit, making full message tracking so hist…
jamesgao Oct 16, 2010
a23e40e
Activated "uparrow" history browsing! simple!
jamesgao Oct 16, 2010
6f1c4f5
Fix up a bunch of movement bugs, allow clickable activate, properly m…
jamesgao Oct 17, 2010
990adfc
Split the JS functions into logical groupings, fix some more bugs
jamesgao Oct 17, 2010
97c2417
Still trying to fix message tracking bugs. SVG works again...
jamesgao Oct 18, 2010
dc0be4b
Massive overhaul of the message tracking interface, bugs remain...
jamesgao Oct 19, 2010
e030733
Fixed the extra pyin connect message bug by deleting all empty messag…
jamesgao Oct 19, 2010
974e5d2
Allow payload to display text, partial support for object inspection.…
jamesgao Oct 19, 2010
c5168d5
Some improved styling, added preliminary history support. Pity the ba…
jamesgao Oct 19, 2010
586a263
Implement a full autocomplete browser. Still need to juggle some more…
jamesgao Oct 20, 2010
a0cf5f8
Add some history support, still need main bug fixed. Tweak scrolling
jamesgao Oct 20, 2010
cce11cd
Multiline entry support
jamesgao Oct 21, 2010
efbcf10
Tweak the styling in the history, delete extraneous print in kernelma…
jamesgao Oct 21, 2010
310913d
Goddamn message tracking still being impossible to deal with, need to
jamesgao Oct 21, 2010
2117482
I think I may have fixed the message tracking bugs. Now, all messages…
jamesgao Oct 21, 2010
c7d81fc
Tweak some styles, fix tab complete with other delimiters
jamesgao Oct 21, 2010
b8c76d1
Managed to fix the indenter, go figure...
jamesgao Oct 21, 2010
fb474f4
Fix a keyerror bug in the kernelmanager, prepare the code for pull re…
jamesgao Oct 21, 2010
77299d3
oops, stupid tabs...
jamesgao Oct 21, 2010
516ff28
Added diff from markvoorhies... linking webpages still not working!
jamesgao Oct 22, 2010
9a75ab3
Change __main__.__file__ to just __file__, now ipython-http knows whe…
jamesgao Oct 22, 2010
c02891f
Changed name of ipython-http per ccordoba12's suggestion, fixed a cli…
jamesgao Oct 27, 2010
ad87ff3
Starting work on the new message tracking design, better support for …
jamesgao Oct 28, 2010
a1ed6cd
Rewrote backend js for new message tracking, works vastly better now
jamesgao Oct 28, 2010
f476146
Do some code reorganization per Fernando's comments
jamesgao Oct 28, 2010
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
80 changes: 80 additions & 0 deletions IPython/frontend/html/CometManager.py
@@ -0,0 +1,80 @@
"""Manages messages for Comet design pattern

COMET design pattern:
http://en.wikipedia.org/wiki/Comet_(programming)

Basic idea -- webpage asks server via a GET request. Server blocks until
something is available, then sends it along to waiting client.
"""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import time
import Queue

#-----------------------------------------------------------------------------
# Constants
#-----------------------------------------------------------------------------
# seconds without heartbeat that client considered dead
client_death = 300

class Manager(object):
"""Tracks msg_id, client get requests for the Comet design pattern"""
def __init__(self):
self.clients = {}
self.req_queue = Queue.Queue()

def register(self, client_id):
self.clients[client_id] = [time.time(), Queue.Queue()]

def __getitem__(self, client_id):
if client_id in self.clients:
return self.clients[client_id][1]
else:
return None

def append(self, msg):
"""Add a message to the queues across all tracked clients"""
for i in self.clients.keys():
dead_for = time.time() - self.clients[i][0]
#Remove client if no heartbeat, otherwise add to its queue
if dead_for > client_death:
del self.clients[i]
else:
self.clients[i][1].put(msg)

def __contains__(self, client_id):
return client_id in self.clients

def heartbeat(self, client_id):
"""Updates the client heartbeat"""
if client_id in self.clients:
self.clients[client_id][0] = time.time()

def connect(self):
#FIXME: better connect method to return execution_count without COMET
return self.kernel_manager.xreq_channel.execute("")

def execute(self, *args):
return self.kernel_manager.xreq_channel.execute(*args)

def complete(self, code, pos):
chunk = re.split('\s|\(|=|;', code[:int(pos)])[-1]
self.kernel_manager.xreq_channel.complete(chunk, code, pos)
return self.req_queue.get()

def inspect(self, oname):
self.kernel_manager.xreq_channel.object_info(oname)
return self.req_queue.get()

def history(self, index = None, raw = False, output=False):
if index == -1:
index = None

self.kernel_manager.xreq_channel.history(index, raw, output)
return self.req_queue.get()

def addreq(self, msg):
"""Adds a message to the immediate-return queue
"""
self.req_queue.put(msg)
Empty file.
18 changes: 18 additions & 0 deletions IPython/frontend/html/css/defaults.css
@@ -0,0 +1,18 @@
body {
font-family:sans-serif;
font-size:10pt;
margin:5px;
}
pre, p { margin:0px; }
.cblue { color: blue }
.ccyan { color: teal }
.cgreen { color: green }
.cyellow { color: #990 }
.cwhite { color: #777 }
.cred { color: red }
.cbold { font-weight:bold }
.hidden { display:none; }
.clear { clear:both; }

.headers { font-size:60%;}
.xreq { font-style:italic }
143 changes: 143 additions & 0 deletions IPython/frontend/html/css/notebook.css
@@ -0,0 +1,143 @@
#messages *,#sidebar * {
border-radius:3px;
-moz-border-radius:3px;
}
#sidebar {
width:20%;
height:100%;
position:fixed;
right:5px;
background:white;
}

.sidebox {
margin:6px;
margin-bottom:36px;
}
.sidebox .inside {
padding:8px;
border:1px solid #CCC;
min-height:20px;
overflow-x:hidden;
overflow-y:auto;
}
.sidebox .title {
margin:-15px 0px -20px 20px;
padding:5px;
float:left;
background:white;
}

/*
* History box
*/
#history { height:30% }
#history .inside {
height:100%;
}
#history .item { width:1024px; }
#history .item > p {
float:left;
margin-right:3px;
}
#history a {
color:#888;
text-decoration:none;
display:block;
float:left;
}
/*
* Status bar
*/
#statusbar {
position:absolute;
bottom:6px;
right:0px;
margin:6px;
padding:8px;
border:1px solid #CCC;
}
#statusbar span { vertical-align:middle; }
#statusbar .bullet {
font-size:150%;
margin-left:10px;
float:right;
}

/*
* Messages
*/
#messages {
width:80%;
float:left;
}
#messages .selected {
background:#CCC;
}
.message {
border:1px solid #CCC;
border-radius:3px;
padding:8px;
margin:6px;
overflow:auto;
}
.message:hover {
border:1px solid red;
cursor:pointer;
}
.active {
border:1px solid #090;
}
.message .input_header {
color:blue;
float:left;
width:10%;
}
.message .input {
float:left;
width:90%;
margin-bottom:4px;
}
.inputText {
font-size:10pt;
width:100%;
padding:0;
border:none;
outline:none;
}
.message .output_header {
color:red;
float:left;
width:10%;
}
.message .output {
float:left;
width:90%;
height:0px;
}


/*
* Tab completer
*/
.completer {
position:absolute;
background:white;
border:1px solid black;
border-bottom-left-radius:3px;
border-bottom-right-radius:3px;
-moz-border-radius-bottomleft:3px;
-moz-border-radius-bottomright:3px;
font-size:8pt;
}
.completer .column {
float:left;
margin:0px 3px;
}
.completer .selection {
padding:2px;
cursor:pointer;
}
.completer .selected {
background-color:#CCC;
}
Binary file added IPython/frontend/html/favicon.ico
Binary file not shown.
100 changes: 100 additions & 0 deletions IPython/frontend/html/ipythonhttp.py
@@ -0,0 +1,100 @@
""" A minimal application using the IPython web notebook frontend.
"""

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

# Local imports
import os
from IPython.external.argparse import ArgumentParser
from IPython.frontend.html.kernelmanager import HttpKernelManager, \
IPyHttpServer, IPyHttpHandler

#-----------------------------------------------------------------------------
# Constants
#-----------------------------------------------------------------------------

LOCALHOST = '127.0.0.1'

#-----------------------------------------------------------------------------
# Main entry point
#-----------------------------------------------------------------------------

def main():
""" Entry point for application.
"""
# Parse command line arguments.
parser = ArgumentParser()
kgroup = parser.add_argument_group('kernel options')
kgroup.add_argument('-e', '--existing', action='store_true',
help='connect to an existing kernel')
kgroup.add_argument('--ip', type=str, default=LOCALHOST,
help='set the kernel\'s IP address [default localhost]')
kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
help='set the XREQ channel port [default random]')
kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
help='set the SUB channel port [default random]')
kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
help='set the REP channel port [default random]')
kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
help='set the heartbeat port [default: random]')

egroup = kgroup.add_mutually_exclusive_group()
egroup.add_argument('--pure', action='store_true', help = \
'use a pure Python kernel instead of an IPython kernel')
egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
const='auto', help = \
"Pre-load matplotlib and numpy for interactive use. If GUI is not \
given, the GUI backend is matplotlib's, otherwise use one of: \
['tk', 'gtk', 'qt', 'wx', 'inline'].")

wgroup = parser.add_argument_group('widget options')
wgroup.add_argument('--paging', type=str, default='inside',
choices = ['inside', 'hsplit', 'vsplit', 'none'],
help='set the paging style [default inside]')
wgroup.add_argument('--rich', action='store_true',
help='enable rich text support')
wgroup.add_argument('--gui-completion', action='store_true',
help='use a GUI widget for tab completion')

args = parser.parse_args()

# Don't let ZMQ swallow KeyboardInterupts.
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

# Create a KernelManager and start a kernel.
kernel_manager = HttpKernelManager(xreq_address=(args.ip, args.xreq),
sub_address=(args.ip, args.sub),
rep_address=(args.ip, args.rep),
hb_address=(args.ip, args.hb))
if args.ip == LOCALHOST and not args.existing:
if args.pure:
kernel_manager.start_kernel(ipython=False)
elif args.pylab:
kernel_manager.start_kernel(pylab=args.pylab)
else:
kernel_manager.start_kernel()
kernel_manager.start_channels()

#Start the web server
server = IPyHttpServer(("", 8080), IPyHttpHandler)
server.serve_forever()

if __name__ == '__main__':
#FIXME: Ctrl-C is not trapped by this try-except, gets lost somewhere in kernel manager
try:
import threading
def defer():
"""Defer the startup of the browser
"""
import time
time.sleep(2)
import webbrowser
webbrowser.open("http://localhost:8080/notebook")
#I need threading here because the main function blocks -- better ideas?
threading.Thread(target=defer).start()
main()
except KeyboardInterrupt:
pass