Quote:
Originally Posted by Venia Legendi
Trying to use an old chain (which has worked AFAIK), I get "EXCEPTION: Formatter: Unknown function set_persistent_vars"?
Problem in front of the screen?
|
Persistent vars functions were removed after the introduction of python templates, which provides better solution if you know python.
I thought no one used them. But if you want to get them back, copy the code below into your module editor:
Code:
from calibre.utils.config import JSONConfig
from calibre_plugins.action_chains.templates.functions.base import TemplateFunction
###########################################
# Persistent Vars
###########################################
persistent_storage = JSONConfig('plugins/action_chains/action-chains-persistent-storage')
# initialize root namespace if not present
if not persistent_storage.get('root_namespace'):
persistent_storage['root_namespace'] = {}
class VarStorage(object):
def __init__(self):
self.root_namespace = persistent_storage['root_namespace']
# prefixes are used to avoid vars overwriting namespaces
self.var_type = 'VAR'
self.ns_type = 'NS'
# Naming rules : {{{{
def mangle_name(self, name, typ):
if not self.validate_name(name):
raise ValueError('Invalid {} name: {}'.format(typ, name))
prefix = '_{}_'.format(typ)
name = name if name.startswith(prefix) else prefix + name
return name
def unmangle_name(self, name, typ):
prefix = '_{}_'.format(typ)
if name.startswith(prefix):
name = name.replace(prefix, '')
return name
def is_var(self, name):
prefix = '_{}_'.format(self.var_type)
if name.startswith(prefix):
return True
return False
def is_namespace(self, name):
prefix = '_{}_'.format(self.ns_type)
if name.startswith(prefix):
return True
return False
def validate_namespace_path(self, namespace_path):
for node in namespace_path:
if not self.validate_name(node):
return False
return True
def validate_name(self, name):
if not name.replace('_', '').isalnum():
return False
return True
def mangle_namespace_path(self, namespace_path):
if not self.validate_namespace_path(namespace_path):
raise ValueError('Invalid namespace path: {}'.format(namespace_path))
mangled_path = []
for node in namespace_path:
mangled_node = self.mangle_name(node, self.ns_type)
mangled_path.append(mangled_node)
return mangled_path
# }}}}
def commit(self):
persistent_storage.commit()
def get_namespace(self, namespace_path=[]):
mangled_path = self.mangle_namespace_path(namespace_path)
ns = self.root_namespace
for node in mangled_path:
try:
ns = ns[node]
except KeyError as e:
raise ValueError('Namespace cannot be found: {}'.format(namespace_path))
return ns
def create_namespace_if_not_present(self, namespace_path=[]):
mangled_path = self.mangle_namespace_path(namespace_path)
ns = self.root_namespace
for node in mangled_path:
if not ns.get(node):
ns[node] = {}
ns = ns[node]
def get_var(self, var_name, namespace_path=[]):
try:
namespace = self.get_namespace(namespace_path)
except:
return ''
name = self.mangle_name(var_name, self.var_type)
return namespace.get(name, '')
def set_var(self, var_name, var_value, namespace_path=[]):
if not isinstance(var_value, str):
raise ValueError('Persistent variable values can only of string type')
self.create_namespace_if_not_present(namespace_path)
namespace = self.get_namespace(namespace_path)
name = self.mangle_name(var_name, self.var_type)
namespace[name] = var_value
self.commit()
def list_vars(self, namespace_path=[]):
namespace = self.get_namespace(namespace_path)
all_vars = []
for name in namespace.keys():
if self.is_var(name):
var = self.unmangle_name(name, self.var_type)
all_vars.append(var)
return all_vars
def list_namespaces(self, namespace_path=[]):
if not namespace_path:
namespace = self.root_namespace
else:
namespace = self.get_namespace(namespace_path)
all_ns = []
for name in namespace.keys():
if self.is_namespace(name):
ns = self.unmangle_name(name, self.ns_type)
all_ns.append(ns)
return all_ns
def delete_namespace(self, namespace_path=[]):
if not namespace_path:
self.root_namespace.clear()
else:
if len(namespace_path) == 1:
parent = self.root_namespace
elif len(namespace_path) > 1:
parent_path = namespace_path[:-1]
parent = self.get_namespace(parent_path)
mangled_name = self.mangle_name(namespace_path[-1], self.ns_type)
del parent[mangled_name]
self.commit()
def delete_var(self, var_name, namespace_path=[]):
namespace = self.get_namespace(namespace_path)
mangled_name = self.mangle_name(var_name, self.var_type)
del namespace[mangled_name]
self.commit()
persistent_vars = VarStorage()
###########################################
# Persistent Vars Template Functions
###########################################
class PersistentVars(TemplateFunction):
doc = _('Retrieve value for variable stored in persistent memory using set_persistent_vars()\n'
'Usage: persistent_vars(var_name, [namespace])\n'
'`var_name`: name of the variable\n'
'`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
'are possible and are represented by dot notation e.g. namespace1.namspace2 '
'If no namespace is provided, the default namespace will be used.\n'
'This function is part of the action chain plugin and will not work elsewhere.')
name = 'persistent_vars'
arg_count = -1
def evaluate(self, formatter, kwargs, mi, locals, *args):
if len(args) not in [1, 2]:
raise ValueError('Incorrect number of arguments')
var_name = args[0]
if len(args) == 2:
namespace_path = args[1].split('.')
else:
namespace_path = []
if not persistent_vars.validate_namespace_path(namespace_path):
raise ValueError('Namespaces must contain only letter, numbers and underscores')
try:
return persistent_vars.get_var(var_name, namespace_path)
except:
# if namespace cannot be found
return ''
class SetPersistentVars(TemplateFunction):
doc = _('Set variables to presistent memory\n'
'Usage: set_persistent_vars(var_name, var_value, [namespace])\n'
'`var_name`: name of the variable\n'
'`var_value`: value of the variable\n'
'`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
'are possible and are represented by dot notation e.g. namespace1.namspace2 '
'If no namespace is provided, the default namespace will be used.\n'
'This function is part of the action chain plugin and will not work elsewhere.')
name = 'set_persistent_vars'
arg_count = -1
def evaluate(self, formatter, kwargs, mi, locals, *args):
if len(args) not in [2, 3]:
raise ValueError('Incorrect number of arguments')
var_name = args[0]
var_value = args[1]
if not persistent_vars.validate_name(var_name):
raise ValueError('Invalid variable name: {}'.format(var_name))
if len(args) == 3:
namespace_path = args[2].split('.')
else:
namespace_path = []
if not persistent_vars.validate_namespace_path(namespace_path):
raise ValueError('Namespaces must contain only letter, numbers and underscores')
# We don't want to write vars when the user is typing in the template
if not self.context == 'template_dialog_mode':
persistent_vars.set_var(var_name, var_value, namespace_path)
return ''
class DeletePersistentVars(TemplateFunction):
doc = _('Delete variable from presistent memory\n'
'Usage: set_persistent_vars(var_name, var_value, [namespace])\n'
'`var_name`: name of the variable\n'
'`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
'are possible and are represented by dot notation e.g. namespace1.namspace2 '
'If no namespace is provided, the default namespace will be used.\n'
'This function is part of the action chain plugin and will not work elsewhere.')
name = 'delete_persistent_vars'
arg_count = -1
def evaluate(self, formatter, kwargs, mi, locals, *args):
if len(args) not in [1, 2]:
raise ValueError('Incorrect number of arguments')
var_name = args[0]
if not persistent_vars.validate_name(var_name):
raise ValueError('Invalid variable name: {}'.format(var_name))
if len(args) == 2:
namespace_path = args[1].split('.')
else:
namespace_path = []
if not persistent_vars.validate_namespace_path(namespace_path):
raise ValueError('Namespaces must contain only letter, numbers and underscores')
# We don't want to delete vars when the user is typing in the template
if not self.context == 'template_dialog_mode':
try:
persistent_vars.delete_var(var_name, namespace_path)
except Exception as e:
import traceback
print(traceback.format_exc())
return ''
class ListPersistentVars(TemplateFunction):
doc = _('List variables stored in presistent memory using set_persistent_vars()\n'
'Usage: list_persistent_vars([namespace])\n'
'`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
'are possible and are represented by dot notation e.g. namespace1.namspace2 '
'If no namespace is provided, the default namespace will be used.\n'
'This function is part of the action chain plugin and will not work elsewhere.')
name = 'list_persistent_vars'
arg_count = -1
def evaluate(self, formatter, kwargs, mi, locals, *args):
if len(args) not in [0, 1]:
raise ValueError('Incorrect number of arguments')
if len(args) == 1:
namespace_path = args[0].split('.')
else:
namespace_path = []
if not persistent_vars.validate_namespace_path(namespace_path):
raise ValueError('Namespaces must contain only letter, numbers and underscores')
all_vars = persistent_vars.list_vars(namespace_path)
return ','.join(all_vars)
class ListPersistentNamespaces(TemplateFunction):
doc = _('List namespaces in presistent memory used by set_persistent_vars()\n'
'Usage: list_persistent_namespaces([namespace])\n'
'`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
'are possible and are represented by dot notation e.g. namespace1.namspace2 '
'If no namespace is provided, all top level namespaces will be listed.\n'
'This function is part of the action chain plugin and will not work elsewhere.')
name = 'list_persistent_namespaces'
arg_count = -1
def evaluate(self, formatter, kwargs, mi, locals, *args):
if len(args) not in [0, 1]:
raise ValueError('Incorrect number of arguments')
if len(args) == 1:
namespace_path = args[0].split('.')
else:
namespace_path = []
if not persistent_vars.validate_namespace_path(namespace_path):
raise ValueError('Namespaces must contain only letter, numbers and underscores')
all_ns = persistent_vars.list_namespaces(namespace_path)
return ','.join(all_ns)
class DeletePersistentNamespaces(TemplateFunction):
doc = _('Delete a namespace in presistent memory used by set_persistent_vars()\n'
'Usage: delete_persistent_namespaces([namespace])\n'
'`namespace`: (optional) namespace where the variable is stored. Nested namespaces '
'are possible and are represented by dot notation e.g. namespace1.namspace2 '
'If no namespace is provided, the top level namespace including all namespaces and '
'vars will be deleted\n'
'This function is part of the action chain plugin and will not work elsewhere.')
name = 'delete_persistent_namespaces'
arg_count = -1
def evaluate(self, formatter, kwargs, mi, locals, *args):
if len(args) not in [0, 1]:
raise ValueError('Incorrect number of arguments')
if len(args) == 1:
namespace_path = args[0].split('.')
else:
namespace_path = []
if not persistent_vars.validate_namespace_path(namespace_path):
raise ValueError('Namespaces must contain only letter, numbers and underscores')
# We don't want to delete namespaces when the user is typing in the template
if not self.context == 'template_dialog_mode':
try:
persistent_vars.delete_namespace(namespace_path)
except Exception as e:
import traceback
print(traceback.format_exc())
return ''