sessionmanager.py
202 lines
| 6.9 KiB
| text/x-python
|
PythonLexer
Zachary Sailer
|
r12985 | """A base class session manager. | ||
Authors: | ||||
* Zach Sailer | ||||
""" | ||||
#----------------------------------------------------------------------------- | ||||
Zachary Sailer
|
r13011 | # Copyright (C) 2013 The IPython Development Team | ||
Zachary Sailer
|
r12985 | # | ||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
import uuid | ||||
Zachary Sailer
|
r13035 | import sqlite3 | ||
Zachary Sailer
|
r12985 | |||
from tornado import web | ||||
from IPython.config.configurable import LoggingConfigurable | ||||
Thomas Kluyver
|
r13353 | from IPython.utils.py3compat import unicode_type | ||
Zachary Sailer
|
r12985 | |||
#----------------------------------------------------------------------------- | ||||
# Classes | ||||
#----------------------------------------------------------------------------- | ||||
class SessionManager(LoggingConfigurable): | ||||
Zachary Sailer
|
r13035 | # Session database initialized below | ||
_cursor = None | ||||
_connection = None | ||||
MinRK
|
r13101 | _columns = {'session_id', 'name', 'path', 'kernel_id', 'ws_url'} | ||
Zachary Sailer
|
r12985 | |||
Zachary Sailer
|
r13035 | @property | ||
def cursor(self): | ||||
"""Start a cursor and create a database called 'session'""" | ||||
if self._cursor is None: | ||||
self._cursor = self.connection.cursor() | ||||
self._cursor.execute("""CREATE TABLE session | ||||
MinRK
|
r13101 | (session_id, name, path, kernel_id, ws_url)""") | ||
Zachary Sailer
|
r13035 | return self._cursor | ||
@property | ||||
def connection(self): | ||||
"""Start a database connection""" | ||||
if self._connection is None: | ||||
self._connection = sqlite3.connect(':memory:') | ||||
MinRK
|
r13101 | self._connection.row_factory = self.row_factory | ||
Zachary Sailer
|
r13035 | return self._connection | ||
def __del__(self): | ||||
"""Close connection once SessionManager closes""" | ||||
self.cursor.close() | ||||
def session_exists(self, name, path): | ||||
MinRK
|
r13101 | """Check to see if the session for a given notebook exists""" | ||
self.cursor.execute("SELECT * FROM session WHERE name=? AND path=?", (name, path)) | ||||
Zachary Sailer
|
r13035 | reply = self.cursor.fetchone() | ||
if reply is None: | ||||
return False | ||||
Zachary Sailer
|
r12985 | else: | ||
Zachary Sailer
|
r13035 | return True | ||
MinRK
|
r13101 | def new_session_id(self): | ||
Zachary Sailer
|
r13035 | "Create a uuid for a new session" | ||
Thomas Kluyver
|
r13353 | return unicode_type(uuid.uuid4()) | ||
Zachary Sailer
|
r13035 | |||
Zachary Sailer
|
r13057 | def create_session(self, name=None, path=None, kernel_id=None, ws_url=None): | ||
"""Creates a session and returns its model""" | ||||
MinRK
|
r13101 | session_id = self.new_session_id() | ||
Zachary Sailer
|
r13057 | return self.save_session(session_id, name=name, path=path, kernel_id=kernel_id, ws_url=ws_url) | ||
def save_session(self, session_id, name=None, path=None, kernel_id=None, ws_url=None): | ||||
"""Saves the items for the session with the given session_id | ||||
Given a session_id (and any other of the arguments), this method | ||||
Zachary Sailer
|
r13035 | creates a row in the sqlite session database that holds the information | ||
for a session. | ||||
Zachary Sailer
|
r12985 | |||
Zachary Sailer
|
r13035 | Parameters | ||
---------- | ||||
session_id : str | ||||
uuid for the session; this method must be given a session_id | ||||
name : str | ||||
the .ipynb notebook name that started the session | ||||
path : str | ||||
the path to the named notebook | ||||
Zachary Sailer
|
r13057 | kernel_id : str | ||
Zachary Sailer
|
r13035 | a uuid for the kernel associated with this session | ||
Zachary Sailer
|
r13057 | ws_url : str | ||
the websocket url | ||||
Returns | ||||
------- | ||||
model : dict | ||||
a dictionary of the session model | ||||
Zachary Sailer
|
r13035 | """ | ||
MinRK
|
r13101 | self.cursor.execute("INSERT INTO session VALUES (?,?,?,?,?)", | ||
(session_id, name, path, kernel_id, ws_url) | ||||
) | ||||
return self.get_session(session_id=session_id) | ||||
Zachary Sailer
|
r13035 | |||
def get_session(self, **kwargs): | ||||
Zachary Sailer
|
r13057 | """Returns the model for a particular session. | ||
Takes a keyword argument and searches for the value in the session | ||||
Zachary Sailer
|
r13035 | database, then returns the rest of the session's info. | ||
Parameters | ||||
---------- | ||||
**kwargs : keyword argument | ||||
must be given one of the keywords and values from the session database | ||||
Zachary Sailer
|
r13057 | (i.e. session_id, name, path, kernel_id, ws_url) | ||
Zachary Sailer
|
r13035 | |||
Returns | ||||
------- | ||||
model : dict | ||||
returns a dictionary that includes all the information from the | ||||
session described by the kwarg. | ||||
""" | ||||
MinRK
|
r13101 | if not kwargs: | ||
raise TypeError("must specify a column to query") | ||||
conditions = [] | ||||
for column in kwargs.keys(): | ||||
if column not in self._columns: | ||||
raise TypeError("No such column: %r", column) | ||||
conditions.append("%s=?" % column) | ||||
query = "SELECT * FROM session WHERE %s" % (' AND '.join(conditions)) | ||||
self.cursor.execute(query, kwargs.values()) | ||||
model = self.cursor.fetchone() | ||||
if model is None: | ||||
q = [] | ||||
for key, value in kwargs.items(): | ||||
q.append("%s=%r" % (key, value)) | ||||
raise web.HTTPError(404, u'Session not found: %s' % (', '.join(q))) | ||||
Zachary Sailer
|
r13035 | return model | ||
def update_session(self, session_id, **kwargs): | ||||
Zachary Sailer
|
r13057 | """Updates the values in the session database. | ||
Changes the values of the session with the given session_id | ||||
Zachary Sailer
|
r13035 | with the values from the keyword arguments. | ||
Zachary Sailer
|
r12985 | |||
Zachary Sailer
|
r13035 | Parameters | ||
---------- | ||||
session_id : str | ||||
a uuid that identifies a session in the sqlite3 database | ||||
**kwargs : str | ||||
the key must correspond to a column title in session database, | ||||
and the value replaces the current value in the session | ||||
with session_id. | ||||
""" | ||||
MinRK
|
r13101 | self.get_session(session_id=session_id) | ||
if not kwargs: | ||||
# no changes | ||||
return | ||||
sets = [] | ||||
for column in kwargs.keys(): | ||||
if column not in self._columns: | ||||
raise TypeError("No such column: %r" % column) | ||||
sets.append("%s=?" % column) | ||||
query = "UPDATE session SET %s WHERE session_id=?" % (', '.join(sets)) | ||||
self.cursor.execute(query, kwargs.values() + [session_id]) | ||||
@staticmethod | ||||
def row_factory(cursor, row): | ||||
Zachary Sailer
|
r13035 | """Takes sqlite database session row and turns it into a dictionary""" | ||
MinRK
|
r13101 | row = sqlite3.Row(cursor, row) | ||
model = { | ||||
'id': row['session_id'], | ||||
'notebook': { | ||||
'name': row['name'], | ||||
'path': row['path'] | ||||
}, | ||||
'kernel': { | ||||
'id': row['kernel_id'], | ||||
'ws_url': row['ws_url'] | ||||
} | ||||
} | ||||
Zachary Sailer
|
r13035 | return model | ||
MinRK
|
r13101 | |||
Zachary Sailer
|
r13035 | def list_sessions(self): | ||
"""Returns a list of dictionaries containing all the information from | ||||
the session database""" | ||||
MinRK
|
r13101 | c = self.cursor.execute("SELECT * FROM session") | ||
return list(c.fetchall()) | ||||
Zachary Sailer
|
r13035 | |||
def delete_session(self, session_id): | ||||
"""Deletes the row in the session database with given session_id""" | ||||
# Check that session exists before deleting | ||||
MinRK
|
r13101 | self.get_session(session_id=session_id) | ||
self.cursor.execute("DELETE FROM session WHERE session_id=?", (session_id,)) | ||||