# ICE Revision: $Id$
"""PermanentStorage
Store data permanently in the metadata of a notebook
"""
from IPython.display import Javascript,display
from PyFoam.ThirdParty.six.moves import cPickle as pickle
import base64
from IPython.utils.py3compat import str_to_bytes, bytes_to_str
from time import sleep
[docs]class PermanentStorage(object):
"""Access the stored values in the notebook
To make sure that only one object is created (so that multiple objects
can't interfer) it is created as a singleton. See:
A python singleton: http://code.activestate.com/recipes/52558/"""
# Value we get from the dark side (Javascript). Technically a global variable. But we're dealing with JavaScript here'
_data={}
# this is so ugly. But I don't know a better way
class __permanentStorage(object):
"""Actual implementation of the storage """
__storePath="IPython.notebook.metadata.pyFoam.storedData"
__outputHandle="""
function handle_output(out){
console.log(out);
var res = null;
// if output is a print statement
if(out.msg_type == "stream"){
res = out.content.data;
}
// if output is a python object
else if(out.msg_type === "pyout"){
res = out.content.data["text/plain"];
}
// if output is a python error
else if(out.msg_type == "pyerr"){
res = out.content.ename + ": " + out.content.evalue;
}
// if output is something we haven't thought of
else{
res = "[out type not implemented]";
}
console.log(res);
}
var callbacks = {'iopub' : {'output' : handle_output}};
"""
def __init__(self):
"""Make sure that there is a subdictionary in the notebook-metadata"""
self.__autowrite=False
self.__autoread=True
display(Javascript(self.__outputHandle+"""
function ensurePyFoamStorage() {
if (typeof IPython =="undefined") {
alert("Trying to use PyFoam.IPythonHelpers.PermanentStorage outside of IPython");
return;
} else if(IPython.notebook==undefined) {
alert("Trying to use PyFoam.IPythonHelpers.PermanentStorage outside of an IPython-notebook");
return;
} else if(IPython.notebook.metadata.pyFoam==undefined) {
IPython.notebook.metadata.pyFoam=Object();
console.log("IPython.notebook.metadata.pyFoam created");
} else {
console.log("IPython.notebook.metadata.pyFoam found");
}
if(IPython.notebook.metadata.pyFoam.storedData==undefined) {
IPython.notebook.metadata.pyFoam.storedData=Object();
console.log("IPython.notebook.metadata.pyFoam.storedData created");
} else {
console.log("IPython.notebook.metadata.pyFoam.storedData found");
}
var store=IPython.notebook.metadata.pyFoam.storedData;
var expr="from PyFoam.IPythonHelpers.PermanentStorage import PermanentStorage as perm\\nperm._data={}";
status="Starting transfer";
var kernel=IPython.notebook.kernel;
kernel.execute(expr, callbacks, {silent:false});
for(var k in store) {
var totalLen=store[k].length;
console.log("Found stored "+k+" Length: "+totalLen);
// expr+="'"+k+"' : '"+store[k]+"' ,";
var chunk=400; // seems to be the best compromise
var nChunks=(totalLen/chunk|0)+1;
for(var i=0;i<nChunks;i++) {
status="chunk "+(i+1)+" of "+nChunks+" of "+k;
var value = store[k].substring(i*chunk,(i+1)*chunk);
var command ="perm._data['"+k+"']";
if(i>0) {
command+="+=";
} else {
command+="=";
}
command += "'"+value+"'";
kernel.execute(command);
}
}
status="Starting transfer (this can take some time)";
console.log("Execution of python done");
}
ensurePyFoamStorage();
"""))
self.__displayModes()
def __getitem__(self,attr):
try:
return pickle.loads(
bytes_to_str(base64.b64decode(str_to_bytes(
PermanentStorage._data[attr]))))
except TypeError as e:
return "TypeError: "+str(e)
def __setitem__(self,attr,value):
"""Set property in the metadata"""
pick=bytes_to_str(base64.b64encode(str_to_bytes(pickle.dumps(value))))
name=attr
PermanentStorage._data[attr]=pick
display(Javascript('%s["%s"]="%s";console.log("Setting %s");' % (self.__storePath,
name,
pick,
name)));
def __delitem__(self,attr):
"""Remove the property from the metadata"""
name=attr
del PermanentStorage._data[attr]
display(Javascript('delete %s.%s;console.log("Deleting %s");' % (self.__storePath,
name,name)));
def __iter__(self):
return PermanentStorage._data.__iter__()
def iterkeys(self):
return PermanentStorage._data.iterkeys()
def keys(self):
return PermanentStorage._data.keys()
def __contains__(self,key):
return key in PermanentStorage._data
def __call__(self,name,f,call=True):
"""Get value or evaluate it.
:param name: name of the item to get/set
:param f: function to evaluate if the item is not present. If
item is not callable (strings for instance) it is set 'as-is'
:param call: Use f() if possible (otherwise f)"""
val=None
if self.__autoread:
try:
val=self[name]
except KeyError:
val=None
if val is None:
if hasattr(f,'__call__') and call:
val=f()
else:
val=f
if self.__autowrite:
self[name]=val
return val
def __displayModes(self):
msg="Storage status: Autowrite: "+str(self.__autowrite)+" Autoread: "+str(self.__autoread)
display(Javascript('status="'+msg+'"'))
def autowriteOn(self):
"""The ()-operator should automatically set the value in the metadata"""
self.__autowrite=True
self.__displayModes()
def autowriteOff(self):
"""The ()-operator should not automatically set the value in the metadata"""
self.__autowrite=False
self.__displayModes()
def autoreadOn(self):
"""The ()-operator should automatically get the value from the metadata"""
self.__autoread=True
self.__displayModes()
def autoreadOff(self):
"""The ()-operator should not automatically get the value from the metadata"""
self.__autoread=False
self.__displayModes()
# storage for the instance reference
__instance = None
def __init__(self):
""" Create the singleon """
# Check whether we already have an instance
if PermanentStorage.__instance is None:
# Create and remember instance
PermanentStorage.__instance = PermanentStorage.__permanentStorage()
# Store instance reference as the only member in the handle
self.__dict__['_PermanentStorage__instance'] = PermanentStorage.__instance
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)
def __getitem__(self,attr):
"""Get property from the metadata"""
return self.__instance.__getitem__(attr)
def __delitem__(self,attr):
"""Delete property from the metadata"""
return self.__instance.__delitem__(attr)
def __iter__(self):
"""Iterate over properties of the metadata"""
return self.__instance.__iter__()
def __contains__(self,key):
"""Is property in the metadata"""
return self.__instance.__contains__(key)
def __setitem__(self,attr,value):
"""Set property in the metadata"""
return self.__instance.__setitem__(attr,value)
def __call__(self,name,f,call=True):
return self.__instance(name,f,call)