sessionmanager.py
206 lines
| 7.4 KiB
| text/x-python
|
PythonLexer
|
r12985 | """A base class session manager. | ||
Authors: | ||||
* Zach Sailer | ||||
""" | ||||
#----------------------------------------------------------------------------- | ||||
|
r13011 | # Copyright (C) 2013 The IPython Development Team | ||
|
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 | ||||
|
r13035 | import sqlite3 | ||
|
r12985 | |||
from tornado import web | ||||
from IPython.config.configurable import LoggingConfigurable | ||||
|
r13353 | from IPython.utils.py3compat import unicode_type | ||
|
r17222 | from IPython.utils.traitlets import Instance | ||
|
r12985 | |||
#----------------------------------------------------------------------------- | ||||
# Classes | ||||
#----------------------------------------------------------------------------- | ||||
class SessionManager(LoggingConfigurable): | ||||
|
r17222 | |||
kernel_manager = Instance('IPython.html.services.kernels.kernelmanager.MappingKernelManager') | ||||
notebook_manager = Instance('IPython.html.services.notebooks.nbmanager.NotebookManager', args=()) | ||||
|
r12985 | |||
|
r13035 | # Session database initialized below | ||
_cursor = None | ||||
_connection = None | ||||
|
r15400 | _columns = {'session_id', 'name', 'path', 'kernel_id'} | ||
|
r12985 | |||
|
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 | ||||
|
r15400 | (session_id, name, path, kernel_id)""") | ||
|
r13035 | return self._cursor | ||
@property | ||||
def connection(self): | ||||
"""Start a database connection""" | ||||
if self._connection is None: | ||||
self._connection = sqlite3.connect(':memory:') | ||||
|
r13101 | self._connection.row_factory = self.row_factory | ||
|
r13035 | return self._connection | ||
def __del__(self): | ||||
"""Close connection once SessionManager closes""" | ||||
self.cursor.close() | ||||
def session_exists(self, name, path): | ||||
|
r13101 | """Check to see if the session for a given notebook exists""" | ||
self.cursor.execute("SELECT * FROM session WHERE name=? AND path=?", (name, path)) | ||||
|
r13035 | reply = self.cursor.fetchone() | ||
if reply is None: | ||||
return False | ||||
|
r12985 | else: | ||
|
r13035 | return True | ||
|
r13101 | def new_session_id(self): | ||
|
r13035 | "Create a uuid for a new session" | ||
|
r13353 | return unicode_type(uuid.uuid4()) | ||
|
r13035 | |||
|
r17222 | def create_session(self, name=None, path=None, kernel_name='python'): | ||
|
r13057 | """Creates a session and returns its model""" | ||
|
r13101 | session_id = self.new_session_id() | ||
|
r17222 | # allow nbm to specify kernels cwd | ||
kernel_path = self.notebook_manager.get_kernel_path(name=name, path=path) | ||||
kernel_id = self.kernel_manager.start_kernel(path=kernel_path, | ||||
kernel_name=kernel_name) | ||||
return self.save_session(session_id, name=name, path=path, | ||||
kernel_id=kernel_id) | ||||
|
r13057 | |||
|
r15400 | def save_session(self, session_id, name=None, path=None, kernel_id=None): | ||
|
r13057 | """Saves the items for the session with the given session_id | ||
Given a session_id (and any other of the arguments), this method | ||||
|
r13035 | creates a row in the sqlite session database that holds the information | ||
for a session. | ||||
|
r12985 | |||
|
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 | ||||
|
r13057 | kernel_id : str | ||
|
r13035 | a uuid for the kernel associated with this session | ||
|
r15400 | |||
|
r13057 | Returns | ||
------- | ||||
model : dict | ||||
a dictionary of the session model | ||||
|
r13035 | """ | ||
|
r15400 | self.cursor.execute("INSERT INTO session VALUES (?,?,?,?)", | ||
(session_id, name, path, kernel_id) | ||||
|
r13101 | ) | ||
return self.get_session(session_id=session_id) | ||||
|
r13035 | |||
def get_session(self, **kwargs): | ||||
|
r13057 | """Returns the model for a particular session. | ||
Takes a keyword argument and searches for the value in the session | ||||
|
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 | ||||
|
r15400 | (i.e. session_id, name, path, kernel_id) | ||
|
r13035 | |||
Returns | ||||
------- | ||||
model : dict | ||||
returns a dictionary that includes all the information from the | ||||
session described by the kwarg. | ||||
""" | ||||
|
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)) | ||||
|
r13377 | self.cursor.execute(query, list(kwargs.values())) | ||
|
r13101 | 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))) | ||||
|
r13035 | return model | ||
def update_session(self, session_id, **kwargs): | ||||
|
r13057 | """Updates the values in the session database. | ||
Changes the values of the session with the given session_id | ||||
|
r13035 | with the values from the keyword arguments. | ||
|
r12985 | |||
|
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. | ||||
""" | ||||
|
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)) | ||||
|
r13377 | self.cursor.execute(query, list(kwargs.values()) + [session_id]) | ||
|
r13101 | |||
|
r17222 | def row_factory(self, cursor, row): | ||
|
r13035 | """Takes sqlite database session row and turns it into a dictionary""" | ||
|
r13101 | row = sqlite3.Row(cursor, row) | ||
model = { | ||||
'id': row['session_id'], | ||||
'notebook': { | ||||
'name': row['name'], | ||||
'path': row['path'] | ||||
}, | ||||
|
r17222 | 'kernel': self.kernel_manager.kernel_model(row['kernel_id']) | ||
|
r13101 | } | ||
|
r13035 | return model | ||
|
r13101 | |||
|
r13035 | def list_sessions(self): | ||
"""Returns a list of dictionaries containing all the information from | ||||
the session database""" | ||||
|
r13101 | c = self.cursor.execute("SELECT * FROM session") | ||
return list(c.fetchall()) | ||||
|
r13035 | |||
def delete_session(self, session_id): | ||||
"""Deletes the row in the session database with given session_id""" | ||||
# Check that session exists before deleting | ||||
|
r17222 | session = self.get_session(session_id=session_id) | ||
self.kernel_manager.shutdown_kernel(session['kernel']['id']) | ||||
|
r13101 | self.cursor.execute("DELETE FROM session WHERE session_id=?", (session_id,)) | ||