Session and Database Management



Session is the main entrance to using libmunin.

It implements a caching layer around the lower level API, being able to save a usage-Session for later re-use. The session data will be saved packed on disk as a .gzip archive.

Apart from this it holds the Mask - in simple words: the part where you tell libmunin what data you have to offer and how you want to configure the processing of it.


class munin.session.Session(name, mask, config={'rebuild_window_size': 60, 'rebuild_refine_passes': 25, 'history_max_rules': 100, 'history_pkg_size': 5, 'history_timeout': 1200, 'max_neighbors': 15, 'recom_history_sieving': True, 'rebuild_step_size': 20, 'recom_history_penalty': {'album': 5, 'artist': 3}, 'rebuild_mean_scale': 2, 'max_distance': 0.999, 'rebuild_stupid_threshold': 350, 'history_max_pkg': 10000})[source]

Main API to libmunin and caching layer.

Create a new session:

  • name – The name of the session. Used to load it again from disk.
  • mask – The mask. See Mask
  • config – A dictionary with config values. See DefaultConfig for available keys.

Return the song with a certain uid.

Raises KeyError:
 On invalid uid.
Returns:a song object which has the same uid attribute.
__init__(name, mask, config={'rebuild_window_size': 60, 'rebuild_refine_passes': 25, 'history_max_rules': 100, 'history_pkg_size': 5, 'history_timeout': 1200, 'max_neighbors': 15, 'recom_history_sieving': True, 'rebuild_step_size': 20, 'recom_history_penalty': {'album': 5, 'artist': 3}, 'rebuild_mean_scale': 2, 'max_distance': 0.999, 'rebuild_stupid_threshold': 350, 'history_max_pkg': 10000})[source]

Create a new session:

  • name – The name of the session. Used to load it again from disk.
  • mask – The mask. See Mask
  • config – A dictionary with config values. See DefaultConfig for available keys.

Iterate over all songs in the database

This is a proxy to Database.__iter__


Get the number of songs currently in the database


list of weak references to the object (if defined)


Add a song with the values in the value_mapping.

This function should be always called like this to trigger a rebuild:

>>> with session.transaction():
...     session.add({'genre': 'death metal', ...})
Parameters:value_mapping (dict) – A mapping Attribute : Value.
Raises KeyError:
 If an unknown Attribute was used.
Returns:The UID of the newly added song.

Return the config dictionary passed to __init__


yield the associated munin.database.Database


Get the munin.distance.DistanceFunction for key

explain_recommendation(seed_song, recommendation, max_reasons=3)[source]

Explain the recommendation you got.

Usage Example:

>>> explain_recommendation(seed_song, recommendation)
(~0.4, [
    ('genre', 0.1),    # Very similar common attribute
    ('moodbar', 0.2),  # Quite similar
    ('lyrics', 0.5)    # Well, that's okay.
  • seed_song – The seed song used. For _heuristic and _attribute this is the first song.
  • recommendation – The recommendation you want to have explained.
  • max_reasons – How many reasons to yield at a maximum.

Tuple of the total distance to each other and a list of pairs that consist of (attribute_name: subdistance_float)


Feed a single song to the history.

If the feeded song is not yet in the database, it will be added automatically.

Parameters:song – The song to feed in the history.
find_matching_attributes(subset, max_numeric_offset=None)[source]

Search the database for a subset of the attributes/values in subset.


>>> find_matching_attributes({'genre': 'metal', 'artist': 'Debauchery'})
# yields songs from Debauchery with that have the exact genre 'metal'

Numeric example:

>>> find_matching_attributes({'rating': 5}, max_numeric_offset=1)
# yield songs with rating 4-5


If max_numeric_offset is used, you may only use attributes that support the __sub__ operator, otherwise a TypeError will be raised.

  • KeyError – if an unknown key is specified in subset.
  • TypeError – if max_numeric_offset is not None and some values do not support substraction.
  • subset – The subset of attributes the songs must have.
  • max_numeric_offset

A lazy iterator over the matching songs.


Fix the previosuly rebuild graph.

This means checking if unsorted distances can be found (which should not happend) and checking if unidirectional edges can be found (which get deleted).

You should this contextmanager when calling insert() or remove().

static from_archive_path(full_path)[source]

Load a cached session from a file on the disk.

Example usage:

>>> Session.from_archive_path('/tmp/test.gz')
<Session object at 0x2343424>


If you prefer to save the sessions in XDG_CACHE_HOME anyway, just use Session.from_name().

Parameters:full_path (str) – a path to a packed session.
Returns:A cached session.
Return type:Session
static from_name(session_name)[source]

Like from_archive_path(), but be clever and load it from ${XDG_CACHE_HOME}/libmunin/<session_name>/session.pickle

Parameters:session_name (str) – The name of a session.
Returns:A cached session.
Return type:Session

Retrieve the index for the key given by key


Insert a song without triggering a rebuild.

This function should be always called like this to trigger a cleanup of the graph:

>>> with session.fix_graph():
...     session.insert({'genre': 'death metal', ...})

The rest is the same as with add().


Retrieve the key of the mask at index idx


Returns a copy of the mask (as passed in)


Returns the length of the attribte mask (number of keys)

modify(song, sub_value_mapping)[source]

Modify an existing and known song by the attributes mentioned in sub_value_mapping.

This should be run during the fix_graph contextmanager.

Usage example:

>>> with session.fix_graph():
...     session.modify(some_song, {'rating': 5})

One usecase is shown in the example, the adjustment of the rating.


This is not a cheap function. The song is removed and all distances to it are recalculated under the hood.


Attention! The returned uid is the same as before, but the underlying song is different. Do not compare by reference!

  • song – The song to modify, either an uid or a
  • sub_value_mapping – A mapping of attributes in values.



Return the name you passed to the session


Get the playcount of a song.

If no playcount is known for it, 0 will be returned.

Returns:Number of times this song was played.
Return type:int

Get all playcounts, or the most common.

Parameters:n – The number of most common plays to select. Might be less.
Returns:A list of tuples if n > 0, or a Mapping.

Get the provider for the key in key

recommend_from_attributes(subset, number=20, max_seeds=10, max_numeric_offset=None)[source]

Find n recommendations solely from intelligent guessing.

This will try to find a good rule, that indicates a user’s favourite song, and will call recommendations_from_seed() on it. If no rules are known, the most played song will be chosen. If there is none, a random song is picked.

The first song in the recommendations yielded is the seed song.

  • subset (dict) – Attribute-Value mapping that seed songs must have.
  • max_seeds – Maximum songs with the subset to get as a base.
  • max_numeric_offset – Same as with find_matching_attributes()

Give ‘n’ recommendations based on ‘song’.

  • Will lookup rules for song.
  • If no rules found, a breadth first search starting with song is performed.
  • Otherwise, breadth first from songs mentioned in the rules are done.

The first song in the recommendations yielded is the seed song.

  • graph (igraph.Graph) – The graph to breadth first search on.
  • rule_index (munin.history.RuleIndex) – Rule database.
  • song ( – Song to base recommendations on.
  • n – Deliver so many recommendations (at max.)

An iterator that yields recommend songs.

recommend_from_seed(song, number=20)[source]

Recommend songs based on a certain attribute.

For example you can search by a certain genre by calling it like this:

>>> recommend_from_attributes({'genre', 'death metal'}, ...)

The value passed must match fully, no fuzzy matching is performed.

Returns:Recommendations like the others or None if no suitable song found.

Remove a single song (or UID) from the Graph.

This function will try to close the hole. If insert() is called afterwards the UID of the deleted song will be re-used.

Returns:The UID of the deleted song.

Save the session (and all caches) to disk.

Parameters:path – Where to save the session in. If none XDG_CACHE_HOME is used.

Return True if sieving is enabled.


Convienience method: Excecute block and call rebuild() afterwards.


Get the weighting (float) for key


class munin.database.Database(session)[source]

Class managing Database concerns.

Usually you access this as .database attribute of munin.session.Session.

You can do the following tasks with it:

  • Trigger updates (rebuild())
  • Get a plot of the graph for debuggin purpose.
  • Iterative over the database (for song in database).
  • Get a song by it’s uid. (database[song.uid])


The division of munin.session.Session and Database is purely cosmetical. Both classes cannot exist on its own.


Lookup a certain song by it’s uid.

Parameters:uid – A uid previously given by
Returns:a, which is a read-only mapping of normalized attributes.
plot(width=1000, height=1000, **kwargs)[source]

Plot the current graph for debugging purpose.

Will try to open an installed image viewer - does not return an image.

  • database – The database (and the assoicate graph with it) to plot.
  • width – Width of the plotted image in pixel.
  • height – Width of the plotted image in pixel.
rebuild(window_size=None, step_size=None, refine_passes=None, stupid_threshold=None)[source]

Rebuild all distances and the associated graph.

This will be triggered for you automatically after a transaction.

  • window_size (int) – The size of the sliding window in the base iteration.
  • step_size (int) – The amount to move the window per iteration.
  • refine_passes (int) – How often step #2 should be repeated.
  • stupid_threshold (int) – If less songs than this just brute forcely calculate all combations of songs.

(Re)build the graph by calculating the combination of all songs.

This is a very expensive operation which takes quadratic time and only should be ever used for a small amount of songs where accuracy matters even more thant time.

Default Config

class munin.session.DefaultConfig


>>> from munin.session import DefaultConfig as default
>>> default.max_neighbors

Alternatively without DefautltConfig:

>>> from munin.session import DEFAULT_CONFIG
>>> DEFAULT_CONFIG['max_neighbors']

The sole purpose of this class is to save a bit of typing.


It is possible to mutate the DEFAULT_CONFIG dict to have the same defaults for every session.

Table Of Contents

Related Topics

This Page

Useful links: