music21.metadata.bundles¶
MetadataBundle¶
- class music21.metadata.bundles.MetadataBundle(expr: 'music21.corpus.corpora.Corpus' | str | None = None)¶
An object that provides access to, searches within, and stores and loads multiple Metadata objects.
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> coreBundle <music21.metadata.bundles.MetadataBundle 'core': {151... entries}>
(The coreBundle has around 15100 entries; I’ve put ‘…’ in the docs so I don’t need to rewrite them every time we add a new piece)
>>> searchResults = coreBundle.search('bach', field='composer') >>> searchResults <music21.metadata.bundles.MetadataBundle {363 entries}>
>>> resultsEntries = searchResults.search('3/4') >>> resultsEntries <music21.metadata.bundles.MetadataBundle {40 entries}>
Results are ordered by their source path:
>>> resultsEntries[0] <music21.metadata.bundles.MetadataEntry 'bach_bwv11_6_mxl'>
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': {151... entries}> >>> coreBundle <music21.metadata.bundles.MetadataBundle 'core': {151... entries}>
Method 3:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> localBundle = corpus.corpora.LocalCorpus().metadataBundle
>>> coreBundle <music21.metadata.bundles.MetadataBundle 'core': {151... 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', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 entries}> >>> tripleMeterBundle = coreBundle.search('3/4') >>> tripleMeterBundle <music21.metadata.bundles.MetadataBundle {1875 entries}> >>> bachBundle.intersection(tripleMeterBundle) <music21.metadata.bundles.MetadataBundle {40 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
bases
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 corpora respectively: (virtual corpus is currently offline)
>>> 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.
Read-only properties inherited from ProtoM21Object
:
MetadataBundle
read/write properties
- MetadataBundle.corpus¶
The corpus.corpora.Corpus object associated with the metadata bundle’s name.
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> coreBundle <music21.metadata.bundles.MetadataBundle 'core': {151... entries}> >>> coreBundle.corpus <music21.corpus.corpora.CoreCorpus>
MetadataBundle
methods
- MetadataBundle.__eq__(other)¶
True if expr is of the same type, and contains an identical set of entries, otherwise false:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> bachBundle = coreBundle.search('bach', 'composer') >>> corelliBundle = coreBundle.search('corelli', 'composer') >>> bachBundle == corelliBundle False >>> bachBundle == coreBundle.search( ... 'bach', ... field='composer', ... ) True >>> bachBundle == 'foo' False
- MetadataBundle.__getitem__(i)¶
- 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.
>>> 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:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> bachBundle = coreBundle.search('bach', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 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:
>>> 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() None ¶
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:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> bachBundle = coreBundle.search('bach', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 entries}>
>>> tripleMeterBundle = coreBundle.search('3/4') >>> tripleMeterBundle <music21.metadata.bundles.MetadataBundle {1875 entries}>
>>> bachBundle.difference(tripleMeterBundle) <music21.metadata.bundles.MetadataBundle {323 entries}>
Returns a new metadata bundle.
- MetadataBundle.intersection(metadataBundle)¶
Compute the set-wise intersection of two metadata bundles:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> bachBundle = coreBundle.search('bach', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 entries}>
>>> tripleMeterBundle = coreBundle.search('3/4') >>> tripleMeterBundle <music21.metadata.bundles.MetadataBundle {1875 entries}>
>>> bachBundle.intersection(tripleMeterBundle) <music21.metadata.bundles.MetadataBundle {40 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:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> bachBundle = coreBundle.search('bach', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 entries}>
>>> corelliBundle = coreBundle.search('corelli', '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:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> bachBundle = coreBundle.search('bach', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 entries}>
>>> tripleMeterBachBundle = bachBundle.search('3/4') >>> tripleMeterBachBundle <music21.metadata.bundles.MetadataBundle {40 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:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> bachBundle = coreBundle.search('bach', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 entries}>
>>> tripleMeterBachBundle = bachBundle.search('3/4') >>> tripleMeterBachBundle <music21.metadata.bundles.MetadataBundle {40 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 ... 'abstract' 'accessRights' 'accompanyingMaterialWriter' ... 'composer' 'composerAlias' 'composerCorporate' 'conceptor' 'conductor' ... 'dateCreated' 'dateFirstPublished' 'dateIssued' 'dateModified' 'dateSubmitted' 'dateValid' ... 'tempoFirst' 'tempos' 'textLanguage' 'textOriginalLanguage' 'timeSignatureFirst' 'timeSignatures' 'title' ...
- 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: str | None = None, field=None, *, fileExtensions: Iterable[str] = (), **keywords)¶
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 difference of two metadata bundles:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> bachBundle = coreBundle.search('bach', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 entries}> >>> tripleMeterBundle = coreBundle.search('3/4') >>> tripleMeterBundle <music21.metadata.bundles.MetadataBundle {1875 entries}> >>> bachBundle.symmetric_difference(tripleMeterBundle) <music21.metadata.bundles.MetadataBundle {2158 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', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 entries}> >>> beethovenBundle = coreBundle.search( ... 'beethoven', ... field='composer', ... ) >>> beethovenBundle <music21.metadata.bundles.MetadataBundle {23 entries}>
>>> bachBundle.union(beethovenBundle) <music21.metadata.bundles.MetadataBundle {386 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.
>>> bachBundle = coreBundle.search('bach', 'composer') >>> bachBundle <music21.metadata.bundles.MetadataBundle {363 entries}> >>> bachBundle.filePath is None True
>>> import os >>> e = environment.Environment() >>> tempFilePath = e.getTempFile() >>> bachBundle.write(filePath=tempFilePath) <music21.metadata.bundles.MetadataBundle {363 entries}> >>> os.remove(tempFilePath)
Methods inherited from ProtoM21Object
:
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:
>>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle >>> metadataEntry = coreBundle.search('bwv66.6')[0] >>> metadataEntry <music21.metadata.bundles.MetadataEntry 'bach_bwv66_6_mxl'>
The sourcePath 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...>
Note that the id is not necessarily the current memory location.
And the metadata entry can be parsed:
>>> metadataEntry.parse() <music21.stream.Score ...>
MetadataEntry
bases
MetadataEntry
read-only properties
- MetadataEntry.corpusName¶
- MetadataEntry.corpusPath¶
- MetadataEntry.metadata¶
Returns the Metadata object that is stored in the bundle.
- MetadataEntry.number¶
- MetadataEntry.sourcePath¶
Read-only properties inherited from ProtoM21Object
:
MetadataEntry
methods
- MetadataEntry.parse()¶
- MetadataEntry.search(query=None, field=None, **keywords)¶
- MetadataEntry.show(showFormat=None)¶
Methods inherited from ProtoM21Object
:
Functions¶
- music21.metadata.bundles.demo_bundle(which: str)¶
This helps with testing by reusing bundles.