I am developing a Calibre's plugin and I want to store user settings (e.g. if the plugin should make a post-import conversion from one format to another - in my
case: pdf
to djvu
).
How can I store user settings? Does Calibre have a build-in method to do this?
For example I have a dictionary prefs_org_dict
with keys and values representing preferences set by an user. How can I store this data reliably and read it later?
The method suggested by the manual is to create the JSONConfig
object and store user preferences in it.
Basically just:
import os
from calibre.utils.config import JSONConfig
prefs = JSONConfig(os.path('plugins', 'PLUGINNAME'))
# JSONConfig inherits after Dict so use it as dictionary
for key, val in prefs_org_dict.iteritems():
prefs[key] = val
prefs.commit() # explanation in 3rd section of this post
But this method has some caveats:
Name of the settings file. Paraphrasing manual:
Remember that this name (i.e.
'plugins/PLUGINNAME'
) is also in a global namespace, so make it as unique as possible. You should always prefix your config file name withplugins/
, so as to ensure you don't accidentally clobber a calibre config file.
After you save anything to this object you can see your PLUGINNAME.json
file inside Calibre's plugin's config folder (for Windows: %APPDATA%\calibre\plugins
) (you can get this path programmatically using: from calibre.utils.config import config_dir
and appending /plugins
).
Default settings.
prefs.defaults
is a dictionary which value is returned if given key doesn't exist in your prefs
object. So you can create some default values for your plugin's settings, e.g.:
prefs.defaults['postimport'] = False
The main problem is when you trying to use other dict methods like .values()
, .items()
or .iteritems()
they return "real" prefs
, not defaults, i.e. for our example, if prefs['postimport']
was not further defined:
>>> prefs.defaults['postimport']
False
>>> prefs.defaults.items()
[('postimport', False)]
>>> prefs['postimport']
False
>>> prefs.items()
[]
Committing nested dict.
If you want to use JSONConfig
object as real .json
storage you probably want to use nested dictionaries. For example:
prefs['pdf'] = {}
prefs['pdf']['convert'] = True
But if you set (or delete) value to nested dictionary prefs['pdf']
it will not be saved to .json
file. You have to:
prefs.commit()
to save data to file after setting them to nested dict.
Constraints of JSON format.
A few of Python features cannot be translated to JSON format, e.g. JSON has not tuples, so json.dumps
translates tuples to arrays. Also in Python you can have an every hashable object (e.g. tuple, or frozenset) as a key. JSON accepts only strings.