music21.metadata.bundles

MetadataBundle

class music21.metadata.bundles.MetadataBundle(expr=None)

An object that provides access to, searches within, and stores and loads multiple Metadata objects.

>>> from music21 import corpus, metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> coreBundle
<music21.metadata.bundles.MetadataBundle 'core': {150... entries}>
>>> searchResults = coreBundle.search('bach', field='composer')
>>> searchResults
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> resultsEntries = searchResults.search('3/4')
>>> resultsEntries
<music21.metadata.bundles.MetadataBundle {6 entries}>

Results are ordered by their source path:

>>> resultsEntries[0]
<music21.metadata.bundles.MetadataEntry: bach_bwv366_krn>

To get a score out of the entry, call .parse()

>>> resultsEntries[0].parse()
<music21.stream.Score ...>

Or pass it into converter:

>>> converter.parse(resultsEntries[0])
<music21.stream.Score ...>

A metadata bundle can be instantiated in three ways, (1) from a Corpus instance, or (2) a string indicating which corpus name to draw from, and then calling .read() or (3) by calling .metadataBundle on a corpus object. This calls .read() automatically:

Method 1:

>>> coreCorpus = corpus.corpora.CoreCorpus()
>>> coreBundle = metadata.bundles.MetadataBundle(coreCorpus)
>>> localCorpus = corpus.corpora.LocalCorpus()
>>> localBundle = metadata.bundles.MetadataBundle(localCorpus)

Method 2:

>>> coreBundle = metadata.bundles.MetadataBundle('core')
>>> localBundle = metadata.bundles.MetadataBundle('local')

After calling these you’ll need to call read():

>>> coreBundle
<music21.metadata.bundles.MetadataBundle 'core': {0 entries}>
>>> coreBundle.read()
<music21.metadata.bundles.MetadataBundle 'core': {150... entries}>
>>> coreBundle
<music21.metadata.bundles.MetadataBundle 'core': {150... entries}>

Method 3:

>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> localBundle = corpus.corpora.LocalCorpus().metadataBundle
>>> coreBundle
<music21.metadata.bundles.MetadataBundle 'core': {150... entries}>

Additionally, any two metadata bundles can be operated on together as though they were sets, allowing us to build up more complex searches:

>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> bachBundle = coreBundle.search(
...     'bach',
...     field='composer',
...     )
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> tripleMeterBundle = coreBundle.search('3/4')
>>> tripleMeterBundle
<music21.metadata.bundles.MetadataBundle {1875 entries}>
>>> bachBundle.intersection(tripleMeterBundle)
<music21.metadata.bundles.MetadataBundle {6 entries}>

Finally, a metadata bundle need not be associated with any corpus at all, and can be populated ad hoc:

>>> anonymousBundle = metadata.bundles.MetadataBundle()
>>> mdb = corpus.corpora.CoreCorpus().search('monteverdi')[:4]
>>> paths = [common.getCorpusFilePath() / x.sourcePath for x in mdb]
>>> failedPaths = anonymousBundle.addFromPaths(
...     paths, useMultiprocessing=False)
>>> failedPaths
[]
>>> anonymousBundle
<music21.metadata.bundles.MetadataBundle {4 entries}>

MetadataBundle read-only properties

MetadataBundle.filePath

The filesystem name of the cached metadata bundle, if the metadata bundle’s name is not None.

>>> ccPath = corpus.corpora.CoreCorpus().metadataBundle.filePath
>>> ccPath.name
'core.p.gz'
>>> '_metadataCache' in ccPath.parts
True
>>> localPath = corpus.corpora.LocalCorpus().metadataBundle.filePath
>>> localPath.name
'local.p.gz'

Local corpora metadata is stored in the scratch dir, not the corpus directory

>>> '_metadataCache' in localPath.parts
False
>>> funkCorpus = corpus.corpora.LocalCorpus('funk')
>>> funkPath = funkCorpus.metadataBundle.filePath
>>> funkPath.name
'local-funk.p.gz'
MetadataBundle.name

The name of the metadata bundle.

Can be ‘core’, ‘local’, ‘{name}’ where name is the name of a named local corpus or None.

The names ‘core’ and ‘local’ refer to the core and local corpuses respectively: (virtual corpus is currently offline)

>>> from music21 import metadata
>>> metadata.bundles.MetadataBundle().name is None
True
>>> corpus.corpora.CoreCorpus().metadataBundle.name
'core'
>>> funkCorpus = corpus.corpora.LocalCorpus('funk')
>>> funkCorpus.metadataBundle.name
'funk'

Return string or None.

MetadataBundle read/write properties

MetadataBundle.corpus

The corpus.corpora.Corpus object associated with the metadata bundle’s name.

>>> from music21 import metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> coreBundle
<music21.metadata.bundles.MetadataBundle 'core': {150... entries}>
>>> coreBundle.corpus
<music21.corpus.corpora.CoreCorpus>

MetadataBundle methods

MetadataBundle.addFromPaths(paths, parseUsingCorpus=False, useMultiprocessing=True, storeOnDisk=True, verbose=False)

Parse and store metadata from numerous files.

If any files cannot be loaded, their file paths will be collected in a list that is returned.

Returns a list of file paths with errors and stores the extracted metadata in self._metadataEntries.

>>> from music21 import corpus, metadata
>>> metadataBundle = metadata.bundles.MetadataBundle()
>>> p = corpus.corpora.CoreCorpus().getWorkList('bach/bwv66.6')
>>> metadataBundle.addFromPaths(
...     p,
...     parseUsingCorpus=False,
...     useMultiprocessing=False,
...     )
[]
>>> len(metadataBundle._metadataEntries)
1

Set Verbose to True to get updates even if debug is off.

MetadataBundle.clear()

Clear all keys in a metadata bundle:

>>> from music21 import metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> bachBundle = coreBundle.search(
...     'bach',
...     field='composer',
...     )
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> bachBundle.clear()
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {0 entries}>

Returns None.

static MetadataBundle.corpusPathToKey(filePath, number=None)

Given a file path or corpus path, return the metadata key:

>>> from music21 import metadata
>>> mb = metadata.bundles.MetadataBundle()
>>> key = mb.corpusPathToKey('bach/bwv1007/prelude')
>>> key.endswith('bach_bwv1007_prelude')
True
>>> key = mb.corpusPathToKey('corelli/opus3no1/1grave.xml')
>>> key.endswith('corelli_opus3no1_1grave_xml')
True
MetadataBundle.delete()

Delete the filesystem cache of a named metadata bundle.

Does not delete the in-memory metadata bundle.

Return none.

MetadataBundle.difference(metadataBundle)

Compute the set-wise difference of two metadata bundles:

>>> from music21 import metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> bachBundle = coreBundle.search(
...     'bach',
...     field='composer',
...     )
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> tripleMeterBundle = coreBundle.search('3/4')
>>> tripleMeterBundle
<music21.metadata.bundles.MetadataBundle {1875 entries}>
>>> bachBundle.difference(tripleMeterBundle)
<music21.metadata.bundles.MetadataBundle {19 entries}>

Returns a new metadata bundle.

MetadataBundle.intersection(metadataBundle)

Compute the set-wise intersection of two metadata bundles:

>>> from music21 import metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> bachBundle = coreBundle.search(
...     'bach',
...     field='composer',
...     )
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> tripleMeterBundle = coreBundle.search('3/4')
>>> tripleMeterBundle
<music21.metadata.bundles.MetadataBundle {1875 entries}>
>>> bachBundle.intersection(tripleMeterBundle)
<music21.metadata.bundles.MetadataBundle {6 entries}>

Returns a new MetadataBundle.

MetadataBundle.isdisjoint(metadataBundle)

True if the set of keys in one metadata bundle are disjoint with the set of keys in another:

>>> from music21 import metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> bachBundle = coreBundle.search(
...     'bach',
...     field='composer',
...     )
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> corelliBundle = coreBundle.search(
...     'corelli',
...     field='composer',
...     )
>>> corelliBundle
<music21.metadata.bundles.MetadataBundle {1 entry}>
>>> bachBundle.isdisjoint(corelliBundle)
True
>>> tripleMeterBundle = coreBundle.search('3/4')
>>> tripleMeterBundle
<music21.metadata.bundles.MetadataBundle {1875 entries}>
>>> bachBundle.isdisjoint(tripleMeterBundle)
False

Returns boolean.

MetadataBundle.issubset(metadataBundle)

True if the set of keys in one metadata bundle are a subset of the keys in another:

>>> from music21 import metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> bachBundle = coreBundle.search(
...     'bach',
...     field='composer',
...     )
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> tripleMeterBachBundle = bachBundle.search('3/4')
>>> tripleMeterBachBundle
<music21.metadata.bundles.MetadataBundle {6 entries}>
>>> tripleMeterBachBundle.issubset(bachBundle)
True
>>> bachBundle.issubset(tripleMeterBachBundle)
False

Returns boolean.

MetadataBundle.issuperset(metadataBundle)

True if the set of keys in one metadata bundle are a superset of the keys in another:

>>> from music21 import metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> bachBundle = coreBundle.search(
...     'bach',
...     field='composer',
...     )
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> tripleMeterBachBundle = bachBundle.search('3/4')
>>> tripleMeterBachBundle
<music21.metadata.bundles.MetadataBundle {6 entries}>
>>> tripleMeterBachBundle.issuperset(bachBundle)
False
>>> bachBundle.issuperset(tripleMeterBachBundle)
True

Returns boolean.

static MetadataBundle.listSearchFields()

List all available search field names:

>>> for field in metadata.bundles.MetadataBundle.listSearchFields():
...     field
...
'actNumber'
'alternativeTitle'
'ambitus'
'associatedWork'
'collectionDesignation'
'commission'
'composer'
'copyright'
'countryOfComposition'
'date'
'dedication'
'groupTitle'
'keySignatureFirst'
'keySignatures'
'localeOfComposition'
'movementName'
'movementNumber'
'noteCount'
'number'
'numberOfParts'
'opusNumber'
'parentTitle'
'pitchHighest'
'pitchLowest'
'popularTitle'
'quarterLength'
'sceneNumber'
'sourcePath'
'tempoFirst'
'tempos'
'textLanguage'
'textOriginalLanguage'
'timeSignatureFirst'
'timeSignatures'
'title'
'volume'
MetadataBundle.read(filePath=None)

Load cached metadata from the file path suggested by the name of this MetadataBundle (‘core’, ‘local’, or a name).

If a specific filepath is given with the filePath keyword, attempt to load cached metadata from the file at that location.

If filePath is None, and self.filePath is also None, do nothing.

>>> coreBundle = metadata.bundles.MetadataBundle('core').read()

If a metadata is unnamed, and no file path is specified, an exception will be thrown:

>>> anonymousBundle = metadata.bundles.MetadataBundle().read()
Traceback (most recent call last):
music21.exceptions21.MetadataException: Unnamed MetadataBundles have
    no default file path to read from.
MetadataBundle.search(query=None, field=None, fileExtensions=None, **kwargs)

Perform search, on all stored metadata, permit regular expression matching.

>>> workList = corpus.corpora.CoreCorpus().getWorkList('ciconia')
>>> metadataBundle = metadata.bundles.MetadataBundle()
>>> failedPaths = metadataBundle.addFromPaths(
...     workList,
...     parseUsingCorpus=False,
...     useMultiprocessing=False,
...     )
>>> failedPaths
[]
>>> searchResult = metadataBundle.search(
...     'cicon',
...     field='composer'
...     )
>>> searchResult
<music21.metadata.bundles.MetadataBundle {1 entry}>
>>> len(searchResult)
1
>>> searchResult[0]
<music21.metadata.bundles.MetadataEntry: ciconia_quod_jactatur_xml>
>>> searchResult = metadataBundle.search(
...     'cicon',
...     field='composer',
...     fileExtensions=('.krn',),
...     )
>>> len(searchResult) # no files in this format
0
>>> searchResult = metadataBundle.search(
...     'cicon',
...     field='composer',
...     fileExtensions=('.xml'),
...     )
>>> len(searchResult)
1

Searches can also use keyword args:

>>> metadataBundle.search(composer='cicon')
<music21.metadata.bundles.MetadataBundle {1 entry}>
MetadataBundle.symmetric_difference(metadataBundle)

Compute the set-wise symmetric differnce of two metadata bundles:

>>> from music21 import metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> bachBundle = coreBundle.search(
...     'bach',
...     field='composer',
...     )
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> tripleMeterBundle = coreBundle.search('3/4')
>>> tripleMeterBundle
<music21.metadata.bundles.MetadataBundle {1875 entries}>
>>> bachBundle.symmetric_difference(tripleMeterBundle)
<music21.metadata.bundles.MetadataBundle {1888 entries}>

Returns a new MetadataBundle.

MetadataBundle.union(metadataBundle)

Compute the set-wise union of two metadata bundles:

>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> bachBundle = coreBundle.search(
...     'bach',
...     field='composer',
...     )
>>> bachBundle
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> beethovenBundle = coreBundle.search(
...     'beethoven',
...     field='composer',
...     )
>>> beethovenBundle
<music21.metadata.bundles.MetadataBundle {20 entries}>
>>> bachBundle.union(beethovenBundle)
<music21.metadata.bundles.MetadataBundle {45 entries}>

Returns a new MetadataBundle.

MetadataBundle.validate()

Validate each metadata entry in a metadata bundle.

If the entry represents a non-virtual corpus asset, test that its source path is locatable on disk. If not, remove the metadata entry from the metadata bundle.

MetadataBundle.write(filePath=None)

Write the metadata bundle to disk as a pickle file.

If filePath is None, use self.filePath.

Returns the metadata bundle.

>>> from music21 import metadata
>>> bachBundle = corpus.corpora.CoreCorpus().metadataBundle.search(
...     'bach',
...     'composer',
...     )
>>> bachBundle.filePath is None
True
>>> import os
>>> import tempfile
>>> tempFilePath = tempfile.mkstemp()[1]
>>> bachBundle.write(filePath=tempFilePath)
<music21.metadata.bundles.MetadataBundle {25 entries}>
>>> os.remove(tempFilePath)

MetadataEntry

class music21.metadata.bundles.MetadataEntry(sourcePath=None, number=None, metadataPayload=None, corpusName=None)

An entry in a metadata bundle.

The metadata entry holds information about the source of the metadata, and can be parsed to reconstitute the score object the metadata was derived from:

>>> from music21 import metadata
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
>>> metadataEntry = coreBundle.search('bwv66.6')[0]
>>> metadataEntry
<music21.metadata.bundles.MetadataEntry: bach_bwv66_6_mxl>

The source path of the metadata entry refers to the file path at which its score file is found:

>>> metadataEntry.sourcePath
PosixPath('bach/bwv66.6.mxl')

The metadata property contains its RichMetadata object:

>>> metadataEntry.metadata
<music21.metadata.RichMetadata object at 0x...>

And the metadata entry can be parsed:

>>> metadataEntry.parse()
<music21.stream.Score ...>

MetadataEntry read-only properties

MetadataEntry.corpusName
MetadataEntry.corpusPath
MetadataEntry.metadata

Returns the Metadata object that is stored in the bundle.

MetadataEntry.number
MetadataEntry.sourcePath

MetadataEntry methods

MetadataEntry.parse()
MetadataEntry.search(query=None, field=None, **kwargs)
MetadataEntry.show(showFormat=None)