Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial publication infrastructure.

  • Loading branch information...
commit 8fedca65afc8dfadc71e82d3d0625a7be1ac4e31 1 parent 16b9fed
@stefanv authored
View
116 IPython/frontend/html/notebook/handlers.py
@@ -19,9 +19,14 @@
import logging
import Cookie
import uuid
+import json
+import ConfigParser
+import StringIO
+import os
from tornado import web
from tornado import websocket
+from tornado import httpclient
from zmq.eventloop import ioloop
from zmq.utils import jsonapi
@@ -577,3 +582,114 @@ def post(self):
self.finish(html)
+
+#-----------------------------------------------------------------------------
+# Publish handler
+#-----------------------------------------------------------------------------
+
+class GitConfigError(Exception):
+ pass
+
+def parse_gitconfig():
+ """Read github username and token from local git configuration.
+
+ Returns
+ -------
+ user, token : str
+ Username, password.
+
+ Raises
+ ------
+ e : GitConfigError
+ If anything goes wrong.
+
+ """
+ try:
+ git_conf = open(os.path.expanduser('~/.gitconfig'), 'r')
+ except (IOError, OSError):
+ raise GitConfigError("Could not open gitconfig.")
+
+ s = StringIO.StringIO()
+ cp = ConfigParser.ConfigParser()
+ try:
+ for l in git_conf.readlines():
+ s.write(l.lstrip())
+ s.seek(0)
+
+ cp.readfp(s)
+ except ConfigParser.ParsingError:
+ raise GitConfigError("Could not parse gitconfig.")
+
+ try:
+ user = cp.get('github', 'user').strip()
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ raise GitConfigError("Could not find github username in gitconfig.")
+
+ try:
+ token = cp.get('github', 'token').strip()
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ raise GitConfigError("Could not find github token in gitconfig.")
+
+ return user, token
+
+class PublishHandler(AuthenticatedHandler):
+
+ @web.authenticated
+ @web.asynchronous
+ def post(self, notebook_id):
+ nbm = self.application.notebook_manager
+ format = self.get_argument('format', default='json')
+ name = self.get_argument('name', default=None)
+ nb = nbm.publish_notebook(notebook_id, self.request.body, name=name,
+ format=format)
+
+ try:
+ user, token = parse_gitconfig()
+ except GitConfigError:
+ self.write(json.dumps(
+ {'status': 'unauthorized',
+ 'message': 'Could not load git configuration'}))
+ self.finish()
+ return
+
+ name = name or 'default'
+
+ data = {
+ "description": name,
+ "public": True,
+ "files": {
+ "%s.ipynb" % name: {
+ "content": nb,
+ }
+ }
+ }
+
+ req = httpclient.HTTPRequest(url="https://api.github.com/gists",
+ method="POST",
+ body=json.dumps(data),
+ auth_username="%s/token" % user,
+ auth_password=token)
+
+ http = httpclient.AsyncHTTPClient()
+ http.fetch(req, self._on_upload)
+
+ def _on_upload(self, response):
+ data = {'status': 'invalid'}
+
+ if response.code in (200, 400, 401, 422):
+ try:
+ result = json.loads(response.body)
+ except:
+ data['message'] = 'Invalid response from github'
+ else:
+ if response.code == 200:
+ data['status'] = 'ok'
+ data['url'] = result['url']
+ else:
+ data['message'] = result.get('message',
+ 'No error description')
+ else:
+ data['message'] = 'GitHub returned %d' % response.code
+
+ self.write(json.dumps(data))
+ self.finish()
View
4 IPython/frontend/html/notebook/notebookapp.py
@@ -43,7 +43,8 @@
from .handlers import (LoginHandler, LogoutHandler,
ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
- ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler
+ ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler,
+ PublishHandler
)
from .notebookmanager import NotebookManager
@@ -97,6 +98,7 @@ def __init__(self, ipython_app, kernel_manager, notebook_manager, log):
(r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
(r"/notebooks", NotebookRootHandler),
(r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
+ (r"/publish/%s" % _notebook_id_regex, PublishHandler),
(r"/rstservice/render", RSTHandler)
]
settings = dict(
View
14 IPython/frontend/html/notebook/notebookmanager.py
@@ -231,3 +231,17 @@ def new_notebook(self):
current.write(nb, f, u'json')
return notebook_id
+ def publish_notebook(self, notebook_id, data, name=None, format=u'json'):
+ """Prepare notebook for publication.
+
+ For now, simply strip out all output cells.
+
+ """
+ try:
+ nb = current.reads(data.decode('utf-8'), format)
+ except:
+ raise web.HTTPError(400, u'Invalid JSON data')
+
+ current.remove_output(nb)
+ return current.writes(nb, format)
+
View
32 IPython/frontend/html/notebook/static/js/notebook.js
@@ -918,6 +918,38 @@ var IPython = (function (IPython) {
return data
};
+ Notebook.prototype.publish_notebook = function () {
+ var notebook_id = IPython.save_widget.get_notebook_id();
+ var nbname = IPython.save_widget.get_notebook_name();
+ var data = this.toJSON();
+ data.metadata.name = nbname;
+ data.nbformat = 2;
+ // We do the call with settings so we can set cache to false.
+ var settings = {
+ processData : false,
+ cache : false,
+ type : "POST",
+ data : JSON.stringify(data),
+ headers : {'Content-Type': 'application/json'},
+ success : $.proxy(this.notebook_published, this),
+// error : $.proxy(this.notebook_save_failed, this)
+ };
+ var url = $('body').data('baseProjectUrl') + 'publish/' + notebook_id
+ $.ajax(url, settings);
+ };
+
+ Notebook.prototype.notebook_published = function (data, status, xhr) {
+ this.dirty = true;
+// IPython.publish_widget.notebook_saved();
+ data = JSON.parse(data);
+ if (data.status != 'ok') {
+ console.log('error message:', data.message);
+ } else {
+ console.log('gist url:', data.url);
+ }
+ }
+
+
Notebook.prototype.save_notebook = function () {
if (IPython.save_widget.test_notebook_name()) {
var notebook_id = IPython.save_widget.get_notebook_id();
View
1  IPython/frontend/html/notebook/static/js/notebookmain.js
@@ -33,6 +33,7 @@ $(document).ready(function () {
IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter');
IPython.save_widget = new IPython.SaveWidget('span#save_widget');
+ IPython.publish_widget = new IPython.PublishWidget('span#publish_widget');
IPython.quick_help = new IPython.QuickHelp('span#quick_help_area');
IPython.login_widget = new IPython.LoginWidget('span#login_widget');
IPython.print_widget = new IPython.PrintWidget('span#print_widget');
View
49 IPython/frontend/html/notebook/static/js/publishwidget.js
@@ -0,0 +1,49 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2008-2011 The IPython Development Team
+//
+// Distributed under the terms of the BSD License. The full license is in
+// the file COPYING, distributed as part of this software.
+//----------------------------------------------------------------------------
+
+//============================================================================
+// PublishWidget
+//============================================================================
+
+var IPython = (function (IPython) {
+
+ var utils = IPython.utils;
+
+ var PublishWidget = function (selector) {
+ this.selector = selector;
+ if (this.selector !== undefined) {
+ this.element = $(selector);
+ this.style();
+ this.bind_events();
+ }
+ };
+
+
+ PublishWidget.prototype.style = function () {
+ this.element.find('button#publish_notebook').button();
+ };
+
+
+ PublishWidget.prototype.bind_events = function () {
+ var that = this;
+ this.element.find('button#publish_notebook').click(function () {
+ that.publish_notebook();
+ });
+ };
+
+
+ PublishWidget.prototype.publish_notebook = function () {
+ IPython.notebook.publish_notebook();
+ };
+
+
+ IPython.PublishWidget = PublishWidget;
+
+ return IPython;
+
+}(IPython));
+
View
4 IPython/frontend/html/notebook/templates/notebook.html
@@ -56,6 +56,9 @@
<input type="text" id="notebook_name" size="20"></textarea>
<button id="save_notebook"><u>S</u>ave</button>
</span>
+ <span id="publish_widget">
+ <button id="publish_notebook">Publish</button>
+ </span>
<span id="quick_help_area">
<button id="quick_help">Quick<u>H</u>elp</button>
</span>
@@ -292,6 +295,7 @@
<script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/printwidget.js" type="text/javascript" charset="utf-8"></script>
+<script src="static/js/publishwidget.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/leftpanel.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/notebook.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/notebookmain.js" type="text/javascript" charset="utf-8"></script>
View
17 IPython/nbformat/current.py
@@ -213,6 +213,23 @@ def write(nb, fp, format, **kwargs):
"""
return fp.write(writes(nb, format, **kwargs))
+
+def remove_output(nb):
+ """Remove output cells from a notebook.
+
+ The notebook is modified in-place.
+
+ Parameters
+ ----------
+ nb : NotebookNode
+ Notebook to clean.
+
+ """
+ for w in nb.worksheets:
+ for c in w.cells:
+ c.outputs = []
+
+
def _convert_to_metadata():
"""Convert to a notebook having notebook metadata."""
import glob
Please sign in to comment.
Something went wrong with that request. Please try again.