Persistent data¶
Alfred provides special data and cache directories for each Workflow (in
~/Library/Application Support
and ~/Library/Caches
respectively).
Workflow
provides the following
attributes/methods to make it easier to access these directories:
datadir
— The full path to your Workflow’s data directory.cachedir
— The full path to your Workflow’s cache directory.datafile(filename)
— The full path tofilename
under the data directory.cachefile(filename)
— The full path tofilename
under the cache directory.
The cache directory may be deleted during system maintenance, and is thus only
suitable for temporary data or data that is easily recreated.
Workflow
‘s cache methods reflect this,
and make it easy to replace cached data that are too old.
See Caching data for details of the data caching API.
The data directory is intended for more permanent, user-generated data, or data that cannot be otherwise easily recreated. See Storing data for details of the data storage API.
It is easy to specify a custom file format for your stored data
via the serializer
argument if you want your data to be readable by the user
or by other software. See Serialization of stored/cached data for more details.
Tip
There are also simliar methods related to the root directory of your
Workflow (where info.plist
and your code are):
workflowdir
— The full path to your Workflow’s root directory.workflowfile(filename)
— The full path tofilename
under your Workflow’s root directory.
These are used internally to implement “Magic” arguments, which provide assistance with debugging, updating and managing your workflow.
In addition, Workflow
also provides a
convenient interface for storing persistent settings with
Workflow.settings
.
See Settings and Keychain access for more
information on storing settings and sensitive data.
Caching data¶
Workflow
provides a few methods to simplify
caching data that is slow to retrieve or expensive to generate (e.g. downloaded
from a web API). These data are cached in your workflow’s cache directory (see
cachedir
). The main method is
Workflow.cached_data()
, which
takes a name under which the data should be cached, a callable to retrieve
the data if they aren’t in the cache (or are too old), and a maximum age in seconds
for the cached data:
1 2 3 4 5 6 7 | from workflow import web, Workflow
def get_data():
return web.get('https://example.com/api/stuff').json()
wf = Workflow()
data = wf.cached_data('stuff', get_data, max_age=600)
|
To retrieve data only if they are in the cache, call with None
as the
data-retrieval function (which is the default):
data = wf.cached_data('stuff', max_age=600)
Note
This will return None
if there are no corresponding data in the cache.
This is useful if you want to update your cache in the background, so it doesn’t impact your Workflow’s responsiveness in Alfred. (See the tutorial for an example of how to run an update script in the background.)
Tip
Passing max_age=0
will return the cached data regardless of age.
Clearing cached data¶
There is a convenience method for clearing a workflow’s cache directory.
clear_cache()
will by default delete all
the files contained in cachedir
. This is
the method called if you use the workflow:delcache
or workflow:reset
magic arguments.
You can selectively delete files from the cache by passing the optional
filter_func
argument to clear_cache()
.
This callable will be called with the filename (not path) of each file in the
workflow’s cache directory.
If filter_func
returns True
, the file will be deleted, otherwise it
will be left in the cache. For example, to delete all .zip
files in the
cache, use:
1 2 3 4 | def myfilter(filename):
return filename.endswith('.zip')
wf.clear_cache(myfilter)
|
or more simply:
1 | wf.clear_cache(lambda f: f.endswith('.zip'))
|
Storing data¶
Workflow
provides two methods to store
and retrieve permanent data:
store_data()
and
stored_data()
.
These data are stored in your workflow’s data directory
(see datadir
).
1 2 3 4 5 6 | from workflow import Workflow
wf = Workflow()
wf.store_data('name', data)
# data will be `None` if there is nothing stored under `name`
data = wf.stored_data('name')
|
These methods do not support the data expiry features of the cached data methods, but you can specify your own serializer for each datastore, making it simple to store data in, e.g., JSON or YAML format.
You should use these methods (and not the data caching ones) if the data you are saving should not be deleted as part of system maintenance.
If you want to specify your own file format/serializer, please see Serialization of stored/cached data for details.
Clearing stored data¶
As with cached data, there is a convenience method for deleting all the files
stored in your workflow’s datadir
.
By default, clear_data()
will delete all the
files stored in datadir
. It is used by the
workflow:deldata
and workflow:reset
magic arguments.
It is possible to selectively delete files contained in the data directory by
supplying the optional filter_func
callable. Please see Clearing cached data
for details on how filter_func
works.
Settings¶
Workflow.settings
is a subclass
of dict
that automatically saves its contents to the settings.json
file in your Workflow’s data directory when it is changed.
Settings
can be used just like a normal dict
with the caveat that all keys and values must be serializable to JSON.
Warning
A Settings
instance can only automatically
recognise when you directly alter the values of its own keys:
1 2 3 | wf = Workflow()
wf.settings['key'] = {'key2': 'value'} # will be automatically saved
wf.settings['key']['key2'] = 'value2' # will *not* be automatically saved
|
If you’ve altered a data structure stored within your workflow’s
Workflow.settings
, you need to
explicitly call Workflow.settings.save()
.
If you need to store arbitrary data, you can use the cached data API.
If you need to store data securely (such as passwords and API keys),
Workflow
also provides simple access to
the OS X Keychain.
Keychain access¶
Methods Workflow.save_password(account, password)
,
Workflow.get_password(account)
and Workflow.delete_password(account)
allow access to the Keychain. They may raise
PasswordNotFound
if no password is set for
the given account
or KeychainError
if
there is a problem accessing the Keychain. Passwords are stored in the user’s
default Keychain. By default, the Workflow’s Bundle ID will be used as the
service name, but this can be overridden by passing the service
argument
to the above methods.
Example usage:
1 2 3 4 5 6 7 8 9 10 11 12 | from workflow import Workflow
wf = Workflow()
wf.save_password('hotmail-password', 'password1lolz')
password = wf.get_password('hotmail-password')
wf.delete_password('hotmail-password')
# raises PasswordNotFound exception
password = wf.get_password('hotmail-password')
|
See the relevant part of the tutorial for a full example.