From fddc4ca07a9e0bec2c52b73d1a41ab54fd29ea44 Mon Sep 17 00:00:00 2001 From: spellew Date: Sun, 9 Jun 2019 21:35:23 -0400 Subject: [PATCH 1/4] Implemented retrieval and/or testing of additional entities (work, label, place, event, release_group) --- brainzutils/musicbrainz_db/artist.py | 10 +- brainzutils/musicbrainz_db/editor.py | 11 +- brainzutils/musicbrainz_db/event.py | 90 +++++++++++ brainzutils/musicbrainz_db/helpers.py | 5 +- brainzutils/musicbrainz_db/includes.py | 2 + brainzutils/musicbrainz_db/label.py | 72 +++++++++ brainzutils/musicbrainz_db/place.py | 82 ++++++++++ brainzutils/musicbrainz_db/recording.py | 31 +++- brainzutils/musicbrainz_db/release.py | 10 +- brainzutils/musicbrainz_db/release_group.py | 153 ++++++++++++++++++ brainzutils/musicbrainz_db/serialize.py | 118 ++++++++++++++ brainzutils/musicbrainz_db/test_data.py | 62 +++++++ .../musicbrainz_db/tests/test_event.py | 30 ++++ .../musicbrainz_db/tests/test_helper.py | 24 +++ .../musicbrainz_db/tests/test_label.py | 38 +++++ .../musicbrainz_db/tests/test_place.py | 33 ++++ .../musicbrainz_db/tests/test_recording.py | 4 +- .../musicbrainz_db/tests/test_release.py | 5 +- .../tests/test_release_group.py | 79 +++++++++ brainzutils/musicbrainz_db/tests/test_work.py | 38 +++++ brainzutils/musicbrainz_db/utils.py | 4 + brainzutils/musicbrainz_db/work.py | 71 ++++++++ 22 files changed, 943 insertions(+), 29 deletions(-) create mode 100644 brainzutils/musicbrainz_db/event.py create mode 100644 brainzutils/musicbrainz_db/label.py create mode 100644 brainzutils/musicbrainz_db/place.py create mode 100644 brainzutils/musicbrainz_db/release_group.py create mode 100644 brainzutils/musicbrainz_db/tests/test_event.py create mode 100644 brainzutils/musicbrainz_db/tests/test_label.py create mode 100644 brainzutils/musicbrainz_db/tests/test_place.py create mode 100644 brainzutils/musicbrainz_db/tests/test_release_group.py create mode 100644 brainzutils/musicbrainz_db/tests/test_work.py create mode 100644 brainzutils/musicbrainz_db/work.py diff --git a/brainzutils/musicbrainz_db/artist.py b/brainzutils/musicbrainz_db/artist.py index 5daa532..eca87de 100644 --- a/brainzutils/musicbrainz_db/artist.py +++ b/brainzutils/musicbrainz_db/artist.py @@ -8,21 +8,19 @@ from brainzutils.musicbrainz_db.includes import check_includes -def get_artist_by_id(mbid): +def get_artist_by_id(mbid, includes=None): """Get artist with MusicBrainz ID. Args: mbid (uuid): MBID(gid) of the artist. Returns: Dictionary containing the artist information """ - artist = _get_artist_by_id(mbid) - return artist - + if includes is None: + includes = [] -def _get_artist_by_id(mbid): return fetch_multiple_artists( [mbid], - includes=['artist-rels', 'url-rels'], + includes=includes, ).get(mbid) diff --git a/brainzutils/musicbrainz_db/editor.py b/brainzutils/musicbrainz_db/editor.py index be10499..16466d6 100644 --- a/brainzutils/musicbrainz_db/editor.py +++ b/brainzutils/musicbrainz_db/editor.py @@ -7,21 +7,19 @@ from brainzutils.musicbrainz_db.includes import check_includes -def get_editor_by_id(editor_id): +def get_editor_by_id(editor_id, includes=None): """Get editor with editor ID. Args: editor_id (int): ID of the editor. Returns: Dictionary containing the editor information """ - editor = _get_editor_by_id(editor_id) - return editor - + if includes is None: + includes = [] -def _get_editor_by_id(editor_id): return fetch_multiple_editors( [editor_id], - includes=[], + includes=includes, ).get(editor_id) @@ -35,6 +33,7 @@ def fetch_multiple_editors(editor_ids, includes=None): """ if includes is None: includes = [] + includes_data = defaultdict(dict) check_includes('editor', includes) with mb_session() as db: diff --git a/brainzutils/musicbrainz_db/event.py b/brainzutils/musicbrainz_db/event.py new file mode 100644 index 0000000..a80ca20 --- /dev/null +++ b/brainzutils/musicbrainz_db/event.py @@ -0,0 +1,90 @@ +from collections import defaultdict +from mbdata import models +from brainzutils.musicbrainz_db import mb_session +from brainzutils.musicbrainz_db.utils import get_entities_by_gids +from brainzutils.musicbrainz_db.includes import check_includes +from brainzutils.musicbrainz_db.serialize import serialize_events +from brainzutils.musicbrainz_db.helpers import get_relationship_info + + +def get_event_by_id(mbid, includes=None): + """Get event with the MusicBrainz ID. + + Args: + mbid (uuid): MBID(gid) of the event. + Returns: + Dictionary containing the event information. + """ + if includes is None: + includes = [] + + return fetch_multiple_events( + [mbid], + includes=includes, + ).get(mbid) + + +def fetch_multiple_events(mbids, includes=None): + """Get info related to multiple events using their MusicBrainz IDs. + + Args: + mbids (list): List of MBIDs of events. + includes (list): List of information to be included. + + Returns: + Dictionary containing info of multiple events keyed by their mbid. + """ + if includes is None: + includes = [] + includes_data = defaultdict(dict) + check_includes('event', includes) + with mb_session() as db: + query = db.query(models.Event) + events = get_entities_by_gids( + query=query, + entity_type='event', + mbids=mbids, + ) + event_ids = [event.id for event in events.values()] + + if 'artist-rels' in includes: + get_relationship_info( + db=db, + target_type='artist', + source_type='event', + source_entity_ids=event_ids, + includes_data=includes_data, + ) + if 'place-rels' in includes: + get_relationship_info( + db=db, + target_type='place', + source_type='event', + source_entity_ids=event_ids, + includes_data=includes_data, + ) + if 'series-rels' in includes: + get_relationship_info( + db=db, + target_type='series', + source_type='event', + source_entity_ids=event_ids, + includes_data=includes_data, + ) + if 'url-rels' in includes: + get_relationship_info( + db=db, + target_type='url', + source_type='event', + source_entity_ids=event_ids, + includes_data=includes_data, + ) + if 'release-group-rels' in includes: + get_relationship_info( + db=db, + target_type='release_group', + source_type='event', + source_entity_ids=event_ids, + includes_data=includes_data, + ) + return {str(mbid): serialize_events(events[mbid], includes_data[events[mbid].id]) for mbid in mbids} diff --git a/brainzutils/musicbrainz_db/helpers.py b/brainzutils/musicbrainz_db/helpers.py index 8556079..5690124 100644 --- a/brainzutils/musicbrainz_db/helpers.py +++ b/brainzutils/musicbrainz_db/helpers.py @@ -59,20 +59,21 @@ def _relationship_link_helper(relation, query, source_attr, target_attr, target_ setdefault(relation_type, []).append(link) -def get_tags(db, entity_model, tag_model, entity_ids): +def get_tags(db, entity_model, tag_model, foreign_tag_id, entity_ids): """Get tags associated with entities. Args: db (Session object): Session object. entity_model (mbdata.models): Model of the entity. tag_model (mbdata.models): Tag of the model. + foreign_tag_id (tag_model.foreign_key): Foreign ID that joins the tag model and entity model entity_ids (list): IDs of the entity whose tags are to be fetched Returns: List of tuples containing the entity_ids and the list of associated tags. """ tags = db.query(entity_model.id, func.array_agg(Tag.name)).\ - join(tag_model).\ + join(tag_model, entity_model.id == foreign_tag_id).\ join(Tag).\ filter(entity_model.id.in_(entity_ids)).\ group_by(entity_model.id).\ diff --git a/brainzutils/musicbrainz_db/includes.py b/brainzutils/musicbrainz_db/includes.py index 35f2860..12a8c91 100644 --- a/brainzutils/musicbrainz_db/includes.py +++ b/brainzutils/musicbrainz_db/includes.py @@ -31,6 +31,8 @@ "artists", "labels", "recordings", "release-groups", "media", "annotation", "aliases" ] + TAG_INCLUDES + RELATION_INCLUDES, 'artist': ["recordings", "releases", "media", "aliases", "annotation"] + RELATION_INCLUDES + TAG_INCLUDES, + 'label': ["aliases", "annotation"] + RELATION_INCLUDES + TAG_INCLUDES, + 'work': ["artists", "recordings", "aliases", "annotation"] + RELATION_INCLUDES + TAG_INCLUDES, 'editor': [], # TODO: List includes here (BU-18) } diff --git a/brainzutils/musicbrainz_db/label.py b/brainzutils/musicbrainz_db/label.py new file mode 100644 index 0000000..a43c0cc --- /dev/null +++ b/brainzutils/musicbrainz_db/label.py @@ -0,0 +1,72 @@ +from collections import defaultdict +from mbdata import models +from sqlalchemy.orm import joinedload +from brainzutils.musicbrainz_db import mb_session +from brainzutils.musicbrainz_db.utils import get_entities_by_gids +from brainzutils.musicbrainz_db.includes import check_includes +from brainzutils.musicbrainz_db.serialize import serialize_labels +from brainzutils.musicbrainz_db.helpers import get_relationship_info + + +def get_label_by_id(mbid, includes=None): + """Get label with the MusicBrainz ID. + + Args: + mbid (uuid): MBID(gid) of the label. + Returns: + Dictionary containing the label information. + """ + if includes is None: + includes = [] + + return fetch_multiple_labels( + [mbid], + includes=includes, + ).get(mbid) + + +def fetch_multiple_labels(mbids, includes=None): + """Get info related to multiple labels using their MusicBrainz IDs. + + Args: + mbids (list): List of MBIDs of labels. + includes (list): List of information to be included. + Returns: + Dictionary containing info of multiple labels keyed by their mbid. + """ + if includes is None: + includes = [] + includes_data = defaultdict(dict) + check_includes('label', includes) + with mb_session() as db: + query = db.query(models.Label).\ + options(joinedload("type")). + + labels = get_entities_by_gids( + query=query, + entity_type='label', + mbids=mbids, + ) + label_ids = [label.id for label in labels.values()] + + if 'artist-rels' in includes: + get_relationship_info( + db=db, + target_type='artist', + source_type='label', + source_entity_ids=label_ids, + includes_data=includes_data, + ) + + if 'url-rels' in includes: + get_relationship_info( + db=db, + target_type='url', + source_type='label', + source_entity_ids=label_ids, + includes_data=includes_data, + ) + + for label in labels.values(): + includes_data[label.id]['type'] = label.type + return {str(mbid): serialize_labels(labels[mbid], includes_data[labels[mbid].id]) for mbid in mbids} diff --git a/brainzutils/musicbrainz_db/place.py b/brainzutils/musicbrainz_db/place.py new file mode 100644 index 0000000..c3298e8 --- /dev/null +++ b/brainzutils/musicbrainz_db/place.py @@ -0,0 +1,82 @@ +from collections import defaultdict +from mbdata import models +from sqlalchemy.orm import joinedload +from brainzutils.musicbrainz_db import mb_session +from brainzutils.musicbrainz_db.includes import check_includes +from brainzutils.musicbrainz_db.serialize import serialize_places +from brainzutils.musicbrainz_db.helpers import get_relationship_info +from brainzutils.musicbrainz_db.utils import get_entities_by_gids + + +def get_place_by_id(mbid, includes=None): + """Get place with the MusicBrainz ID. + + Args: + mbid (uuid): MBID(gid) of the place. + Returns: + Dictionary containing the place information. + """ + if includes is None: + includes = [] + + return fetch_multiple_places( + [mbid], + includes=includes, + ).get(mbid) + + +def fetch_multiple_places(mbids, includes=None): + """Get info related to multiple places using their MusicBrainz IDs. + + Args: + mbids (list): List of MBIDs of places. + includes (list): List of information to be included. + + Returns: + Dictionary containing info of multiple places keyed by their mbid. + """ + if includes is None: + includes = [] + includes_data = defaultdict(dict) + check_includes('place', includes) + with mb_session() as db: + query = db.query(models.Place).\ + options(joinedload("area")).\ + options(joinedload("type")) + places = get_entities_by_gids( + query=query, + entity_type='place', + mbids=mbids, + ) + place_ids = [place.id for place in places.values()] + + if 'artist-rels' in includes: + get_relationship_info( + db=db, + target_type='artist', + source_type='place', + source_entity_ids=place_ids, + includes_data=includes_data, + ) + if 'place-rels' in includes: + get_relationship_info( + db=db, + target_type='place', + source_type='place', + source_entity_ids=place_ids, + includes_data=includes_data, + ) + if 'url-rels' in includes: + get_relationship_info( + db=db, + target_type='url', + source_type='place', + source_entity_ids=place_ids, + includes_data=includes_data, + ) + + for place in places.values(): + includes_data[place.id]['area'] = place.area + includes_data[place.id]['type'] = place.type + places = {str(mbid): serialize_places(places[mbid], includes_data[places[mbid].id]) for mbid in mbids} + return places diff --git a/brainzutils/musicbrainz_db/recording.py b/brainzutils/musicbrainz_db/recording.py index b9d49ee..6d03a04 100644 --- a/brainzutils/musicbrainz_db/recording.py +++ b/brainzutils/musicbrainz_db/recording.py @@ -20,8 +20,11 @@ def get_recording_by_mbid(mbid, includes=None): """ if includes is None: includes = [] - recording = get_many_recordings_by_mbid([mbid], includes) - return recording.get(mbid) + return fetch_multiple_recordings( + [mbid], + includes=includes, + ).get(mbid) + def get_many_recordings_by_mbid(mbids, includes=None): """ Get multiple recordings with MusicBrainz IDs. It fetches recordings @@ -37,12 +40,10 @@ def get_many_recordings_by_mbid(mbids, includes=None): if includes is None: includes = [] - recordings = _fetch_multiple_recordings(mbids, includes) - - return recordings + return fetch_multiple_recordings(mbids, includes) -def _fetch_multiple_recordings(mbids, includes=None): +def fetch_multiple_recordings(mbids, includes=None): """ Fetch multiple recordings with MusicBrainz IDs. Args: @@ -89,6 +90,24 @@ def _fetch_multiple_recordings(mbids, includes=None): for recording in recordings.values(): includes_data[recording.id]['artists'] = recording.artist_credit.artists + if 'url-rels' in includes: + get_relationship_info( + db=db, + target_type='url', + source_type='recording', + source_entity_ids=recording_ids, + includes_data=includes_data, + ) + + if 'work-rels' in includes: + get_relationship_info( + db=db, + target_type='work', + source_type='recording', + source_entity_ids=recording_ids, + includes_data=includes_data, + ) + serial_recordings = {str(mbid): serialize_recording(recordings[mbid], includes_data[recordings[mbid].id]) for mbid in mbids} return serial_recordings diff --git a/brainzutils/musicbrainz_db/release.py b/brainzutils/musicbrainz_db/release.py index 0adcbee..1c29196 100644 --- a/brainzutils/musicbrainz_db/release.py +++ b/brainzutils/musicbrainz_db/release.py @@ -10,21 +10,19 @@ from brainzutils.musicbrainz_db import recording -def get_release_by_id(mbid): +def get_release_by_id(mbid, includes=None): """Get release with the MusicBrainz ID. Args: mbid (uuid): MBID(gid) of the release. Returns: Dictionary containing the release information. """ - release = _get_release_by_id(mbid) - return release - + if includes is None: + includes = [] -def _get_release_by_id(mbid): return fetch_multiple_releases( [mbid], - includes=['media', 'release-groups'], + includes=includes, ).get(mbid) diff --git a/brainzutils/musicbrainz_db/release_group.py b/brainzutils/musicbrainz_db/release_group.py new file mode 100644 index 0000000..78acea0 --- /dev/null +++ b/brainzutils/musicbrainz_db/release_group.py @@ -0,0 +1,153 @@ +from collections import defaultdict +from mbdata import models +from sqlalchemy import case +from sqlalchemy.orm import joinedload +from brainzutils.musicbrainz_db import mb_session +from brainzutils.musicbrainz_db.includes import check_includes +from brainzutils.musicbrainz_db.serialize import serialize_release_groups +from brainzutils.musicbrainz_db.utils import get_entities_by_gids +from brainzutils.musicbrainz_db.helpers import get_relationship_info, get_tags + + +def get_release_group_by_id(mbid, includes=None): + """Get release group with the MusicBrainz ID. + Args: + mbid (uuid): MBID(gid) of the release group. + Returns: + Dictionary containing the release group information. + """ + if includes is None: + includes = [] + + return fetch_multiple_release_groups( + [mbid], + includes=includes, + ).get(mbid) + + +def fetch_multiple_release_groups(mbids, includes=None): + """Get info related to multiple release groups using their MusicBrainz IDs. + Args: + mbids (list): List of MBIDs of releases groups. + includes (list): List of information to be included. + Returns: + Dictionary containing info of multiple release groups keyed by their mbid. + """ + if includes is None: + includes = [] + includes_data = defaultdict(dict) + check_includes('release_group', includes) + with mb_session() as db: + # Join table meta which contains release date for a release group + query = db.query(models.ReleaseGroup).options(joinedload("meta")).\ + options(joinedload("type")) + + if 'artists' in includes: + query = query.\ + options(joinedload("artist_credit")).\ + options(joinedload("artist_credit.artists")).\ + options(joinedload("artist_credit.artists.artist")) + + release_groups = get_entities_by_gids( + query=query, + entity_type='release_group', + mbids=mbids, + ) + release_group_ids = [release_group.id for release_group in release_groups.values()] + + if 'artists' in includes: + for release_group in release_groups.values(): + artist_credit_names = release_group.artist_credit.artists + includes_data[release_group.id]['artist-credit-names'] = artist_credit_names + includes_data[release_group.id]['artist-credit-phrase'] = release_group.artist_credit.name + + if 'releases' in includes: + query = db.query(models.Release).filter(getattr(models.Release, "release_group_id").in_(release_group_ids)) + for release in query: + includes_data[release.release_group_id].setdefault('releases', []).append(release) + + if 'release-group-rels' in includes: + get_relationship_info( + db=db, + target_type='release_group', + source_type='release_group', + source_entity_ids=release_group_ids, + includes_data=includes_data, + ) + + if 'url-rels' in includes: + get_relationship_info( + db=db, + target_type='url', + source_type='release_group', + source_entity_ids=release_group_ids, + includes_data=includes_data, + ) + + if 'work-rels' in includes: + get_relationship_info( + db=db, + target_type='work', + source_type='release_group', + source_entity_ids=release_group_ids, + includes_data=includes_data, + ) + + if 'tags' in includes: + release_group_tags = get_tags( + db=db, + entity_model=models.ReleaseGroup, + tag_model=models.ReleaseGroupTag, + foreign_tag_id=models.ReleaseGroupTag.release_group_id, + entity_ids=release_group_ids, + ) + for release_group_id, tags in release_group_tags: + includes_data[release_group_id]['tags'] = tags + + for release_group in release_groups.values(): + includes_data[release_group.id]['meta'] = release_group.meta + includes_data[release_group.id]['type'] = release_group.type + release_groups = {str(mbid): serialize_release_groups(release_groups[mbid], includes_data[release_groups[mbid].id]) + for mbid in mbids} + return release_groups + + +def get_release_groups_for_artist(artist_id, release_types=None, limit=None, offset=None): + """Get all release groups linked to an artist. + + Args: + artist_id (uuid): MBID of the artist. + release_types (list): List of types of release groups to be fetched. + limit (int): Max number of release groups to return. + offset (int): Offset that can be used in conjunction with the limit. + + Returns: + Tuple containing the list of dictionaries of release groups ordered by release year + and the total count of the release groups. + """ + artist_id = str(artist_id) + includes_data = defaultdict(dict) + if release_types is None: + release_types = [] + release_types = [release_type.capitalize() for release_type in release_types] + with mb_session() as db: + release_groups_query = _get_release_groups_for_artist_query(db, artist_id, release_types) + count = release_groups_query.count() + release_groups = release_groups_query.order_by( + case([(models.ReleaseGroupMeta.first_release_date_year.is_(None), 1)], else_=0), + models.ReleaseGroupMeta.first_release_date_year.desc() + ).limit(limit).offset(offset).all() + for release_group in release_groups: + includes_data[release_group.id]['meta'] = release_group.meta + release_groups = ([serialize_release_groups(release_group, includes_data[release_group.id]) + for release_group in release_groups], count) + return release_groups + + +def _get_release_groups_for_artist_query(db, artist_id, release_types): + return db.query(models.ReleaseGroup).\ + options(joinedload('meta')).\ + join(models.ReleaseGroupPrimaryType).join(models.ReleaseGroupMeta).\ + join(models.ArtistCreditName, models.ArtistCreditName.artist_credit_id == models.ReleaseGroup.artist_credit_id).\ + join(models.Artist, models.Artist.id == models.ArtistCreditName.artist_id).\ + filter(models.Artist.gid == artist_id).filter(models.ReleaseGroupPrimaryType.name.in_(release_types)) diff --git a/brainzutils/musicbrainz_db/serialize.py b/brainzutils/musicbrainz_db/serialize.py index 74c8fd4..2201f4b 100644 --- a/brainzutils/musicbrainz_db/serialize.py +++ b/brainzutils/musicbrainz_db/serialize.py @@ -3,6 +3,19 @@ from sqlalchemy_dst import row2dict +def serialize_areas(area, includes=None): + if includes is None: + includes = {} + data = { + 'id': area.gid, + 'name': area.name, + } + + if 'relationship_objs' in includes: + serialize_relationships(data, area, includes['relationship_objs']) + return data + + def serialize_relationships(data, source_obj, relationship_objs): """Convert relationship objects to dictionaries. @@ -83,6 +96,52 @@ def serialize_recording(recording, includes=None): return data +def serialize_places(place, includes=None): + if includes is None: + includes = {} + data = { + 'id': place.gid, + 'name': place.name, + 'address': place.address, + } + + if 'type' in includes and includes['type']: + data['type'] = includes['type'].name + + if place.coordinates: + data['coordinates'] = { + 'latitude': place.coordinates[0], + 'longitude': place.coordinates[1], + } + + if 'area' in includes and includes['area']: + data['area'] = serialize_areas(includes['area']) + + if 'relationship_objs' in includes: + serialize_relationships(data, place, includes['relationship_objs']) + return data + + +def serialize_labels(label, includes=None): + if includes is None: + includes = {} + data = { + 'id': label.gid, + 'name': label.name, + } + + if label.comment: + data['comment'] = label.comment + + if 'type' in includes and includes['type']: + data['type'] = includes['type'].name + + if 'relationship_objs' in includes: + serialize_relationships(data, label, includes['relationship_objs']) + + return data + + def serialize_artists(artist, includes=None): if includes is None: includes = {} @@ -100,6 +159,16 @@ def serialize_artists(artist, includes=None): return data +def serialize_artist_credit_names(artist_credit_name): + data = { + 'name': artist_credit_name.name, + 'artist': serialize_artists(artist_credit_name.artist), + } + if artist_credit_name.join_phrase: + data['join_phrase'] = artist_credit_name.join_phrase + return data + + def serialize_release_groups(release_group, includes=None): if includes is None: includes = {} @@ -185,6 +254,18 @@ def serialize_releases(release, includes=None): return data +def serialize_events(event, includes=None): + if includes is None: + includes = {} + data = { + 'id': event.gid, + 'name': event.name, + } + if 'relationship_objs' in includes: + serialize_relationships(data, event, includes['relationship_objs']) + return data + + def serialize_url(url, includes=None): if includes is None: includes = {} @@ -198,6 +279,23 @@ def serialize_url(url, includes=None): return data +def serialize_works(work, includes=None): + if includes is None: + includes = {} + data = { + 'id': work.gid, + 'name': work.name, + } + + if 'type' in includes and includes['type']: + data['type'] = includes['type'].name + + if 'relationship_objs' in includes: + serialize_relationships(data, work, includes['relationship_objs']) + + return data + + def serialize_editor(editor, includes=None): data = row2dict(editor, exclude_pk=True, exclude={'password', 'ha1'}) @@ -206,6 +304,21 @@ def serialize_editor(editor, includes=None): return data +def serialize_series(series, includes=None): + if includes is None: + includes = [] + + data = { + 'id': series.gid, + 'name': series.name, + } + + if 'relationship_objs' in includes: + serialize_relationships(data, series, includes['relationship_objs']) + + return data + + SERIALIZE_ENTITIES = { 'artist': serialize_artists, 'release_group': serialize_release_groups, @@ -213,4 +326,9 @@ def serialize_editor(editor, includes=None): 'medium': serialize_medium, 'url': serialize_url, 'editor': serialize_editor, + 'recording': serialize_recording, + 'place': serialize_places, + 'area': serialize_areas, + 'event': serialize_events, + 'series': serialize_series, } diff --git a/brainzutils/musicbrainz_db/test_data.py b/brainzutils/musicbrainz_db/test_data.py index 2d4e939..ce272c4 100644 --- a/brainzutils/musicbrainz_db/test_data.py +++ b/brainzutils/musicbrainz_db/test_data.py @@ -21,13 +21,51 @@ ReleaseGroupMeta, ReleaseGroupPrimaryType, ReleaseStatus, + Label, + LabelType, Script, Event, EventType, Track, Editor, + Work, + WorkType ) +# Label (1aed8c3b-8e1e-46f8-b558-06357ff5f298) +labeltype_imprint = LabelType() +labeltype_imprint.id = 9 +labeltype_imprint.name = 'Imprint' +labeltype_imprint.description = None +labeltype_imprint.gid = 'b6285b2a-3514-3d43-80df-fcf528824ded' + +label_dreamville = Label() +label_dreamville.id = 100653 +label_dreamville.gid = '1aed8c3b-8e1e-46f8-b558-06357ff5f298' +label_dreamville.name = 'Dreamville' +label_dreamville.comment = '' +label_dreamville.ended = False +label_dreamville.label_code = None +label_dreamville.begin_date_year = 2007 +label_dreamville.type = labeltype_imprint + +# Label (4cccc72a-0bd0-433a-905e-dad87871397d) +labeltype_original_production = LabelType() +labeltype_original_production.id = 4 +labeltype_original_production.name = 'Original Production' +labeltype_original_production.description = None +labeltype_original_production.gid = '7aaa37fe-2def-3476-b359-80245850062d' + +label_roc_a_fella = Label() +label_roc_a_fella.id = 4596 +label_roc_a_fella.gid = '4cccc72a-0bd0-433a-905e-dad87871397d' +label_roc_a_fella.name = 'Roc-A-Fella Records' +label_roc_a_fella.comment = '' +label_roc_a_fella.ended = False +label_roc_a_fella.label_code = None +label_roc_a_fella.begin_date_year = 1996 +label_roc_a_fella.type = labeltype_original_production + # Place (d71ffe38-5eaf-426b-9a2e-e1f21bc84609) with url-rels, place-rels area_hameenlinna = Area() area_hameenlinna.id = 9598 @@ -442,3 +480,27 @@ last_login_date=editor_dt, last_updated=editor_dt, birth_date=editor_date, deleted=False, area=area_hameenlinna, password="$2b$12$2odiKUAGktuwM2J.tp/uZ.54bniapSMjCln3J1TfC6zx74QFuawQ6", ha1="3f3edade87115ce351d63f42d92a1834") + +# Work (54ce5e07-2aca-4578-83d8-5a41a7b2f434) +worktype_song = WorkType() +worktype_song.id = 17 +worktype_song.name = 'Song' +worktype_song.description = 'A song is in its origin (and still in most cases) a composition for voice, with or ' \ + 'without instruments, performedby singing. This is the most common form by far in ' \ + 'folk and popular music, but also fairly common in a classical context("art songs").' +worktype_song.gid = 'f061270a-2fd6-32f1-a641-f0f8676d14e6' + +work_a_lot = Work() +work_a_lot.id = 13378753 +work_a_lot.gid = '54ce5e07-2aca-4578-83d8-5a41a7b2f434' +work_a_lot.name = 'a lot' +work_a_lot.comment = '' +work_a_lot.type = worktype_song + +# Work (757504fb-a130-4b84-9eb5-1b37164f12dd) +work_aquemini = Work() +work_aquemini.id = 12521050 +work_aquemini.gid = '757504fb-a130-4b84-9eb5-1b37164f12dd' +work_aquemini.name = 'Aquemini' +work_aquemini.comment = '' +work_aquemini.type = worktype_song diff --git a/brainzutils/musicbrainz_db/tests/test_event.py b/brainzutils/musicbrainz_db/tests/test_event.py new file mode 100644 index 0000000..540e354 --- /dev/null +++ b/brainzutils/musicbrainz_db/tests/test_event.py @@ -0,0 +1,30 @@ +from unittest import TestCase +from mock import MagicMock +from brainzutils.musicbrainz_db import event as mb_event +from brainzutils.musicbrainz_db.test_data import taubertal_festival_2004, event_ra_hall_uk + + +class EventTestCase(TestCase): + + def setUp(self): + mb_event.mb_session = MagicMock() + self.mock_db = mb_event.mb_session.return_value.__enter__.return_value + self.event_query = self.mock_db.query.return_value.filter.return_value.all + + def test_get_event_by_id(self): + self.event_query.return_value = [taubertal_festival_2004] + event = mb_event.get_event_by_id('ebe6ce0f-22c0-4fe7-bfd4-7a0397c9fe94') + self.assertDictEqual(event, { + 'id': 'ebe6ce0f-22c0-4fe7-bfd4-7a0397c9fe94', + 'name': 'Taubertal-Festival 2004, Day 1', + }) + + def test_fetch_multiple_events(self): + self.event_query.return_value = [taubertal_festival_2004, event_ra_hall_uk] + events = mb_event.fetch_multiple_events( + ['ebe6ce0f-22c0-4fe7-bfd4-7a0397c9fe94', '40e6153d-a042-4c95-a0a9-b0a47e3825ce'], + ) + self.assertEqual(events['ebe6ce0f-22c0-4fe7-bfd4-7a0397c9fe94']['name'], + 'Taubertal-Festival 2004, Day 1') + self.assertEqual(events['40e6153d-a042-4c95-a0a9-b0a47e3825ce']['name'], + '1996-04-17: Royal Albert Hall, London, England, UK') diff --git a/brainzutils/musicbrainz_db/tests/test_helper.py b/brainzutils/musicbrainz_db/tests/test_helper.py index 853c4dc..0e7a36f 100644 --- a/brainzutils/musicbrainz_db/tests/test_helper.py +++ b/brainzutils/musicbrainz_db/tests/test_helper.py @@ -1,9 +1,11 @@ from collections import defaultdict from unittest import TestCase from mock import MagicMock +from mbdata import models from brainzutils.musicbrainz_db.serialize import serialize_relationships from brainzutils.musicbrainz_db.helpers import get_relationship_info import brainzutils.musicbrainz_db as mb +from brainzutils.musicbrainz_db.helpers import get_tags from brainzutils.musicbrainz_db.test_data import linkplaceurl_1, linkplaceurl_2, place_suisto @@ -12,9 +14,31 @@ class HelpersTestCase(TestCase): def setUp(self): mb.mb_session = MagicMock() self.mock_db = mb.mb_session.return_value.__enter__.return_value + self.tags_query = self.mock_db.query.return_value.join.return_value.\ + join.return_value.filter.return_value.group_by.return_value.all self.relationships_query = self.mock_db.query.return_value.options.return_value.\ options.return_value.filter.return_value.options + def test_get_tags(self): + data = defaultdict(dict) + self.tags_query.return_value = [(1820974, ['hip hop', 'hip-hop/rap'])] + release_group_tags = get_tags( + db=self.mock_db, + entity_model=models.ReleaseGroup, + tag_model=models.ReleaseGroupTag, + foreign_tag_id=models.ReleaseGroupTag.release_group_id, + entity_ids=['1820974'], + ) + for release_group_id, tags in release_group_tags: + data[release_group_id]['tags'] = tags + expected_data = { + 1820974: { + 'tags': ['hip hop', 'hip-hop/rap'] + } + } + data = dict(data) + self.assertDictEqual(data, expected_data) + def test_get_relationship_info(self): data = {} self.relationships_query.return_value = [linkplaceurl_1, linkplaceurl_2] diff --git a/brainzutils/musicbrainz_db/tests/test_label.py b/brainzutils/musicbrainz_db/tests/test_label.py new file mode 100644 index 0000000..7f6b2eb --- /dev/null +++ b/brainzutils/musicbrainz_db/tests/test_label.py @@ -0,0 +1,38 @@ +from unittest import TestCase +from mock import MagicMock +from brainzutils.musicbrainz_db.test_data import label_dreamville, label_roc_a_fella +from brainzutils.musicbrainz_db import label as mb_label + + +class LabelTestCase(TestCase): + + def setUp(self): + mb_label.mb_session = MagicMock() + self.mock_db = mb_label.mb_session.return_value.__enter__.return_value + self.label_query = self.mock_db.query.return_value.options.return_value.filter.return_value.all + + def test_get_label_by_id(self): + self.label_query.return_value = [label_dreamville] + label = mb_label.get_label_by_id('1aed8c3b-8e1e-46f8-b558-06357ff5f298') + self.assertDictEqual(label, { + "id": "1aed8c3b-8e1e-46f8-b558-06357ff5f298", + "name": "Dreamville", + "type": "Imprint", + }) + + def test_fetch_multiple_labels(self): + self.label_query.return_value = [label_dreamville, label_roc_a_fella] + labels = mb_label.fetch_multiple_labels([ + '1aed8c3b-8e1e-46f8-b558-06357ff5f298', + '4cccc72a-0bd0-433a-905e-dad87871397d' + ]) + self.assertDictEqual(labels["1aed8c3b-8e1e-46f8-b558-06357ff5f298"], { + "id": "1aed8c3b-8e1e-46f8-b558-06357ff5f298", + "name": "Dreamville", + "type": "Imprint", + }) + self.assertDictEqual(labels["4cccc72a-0bd0-433a-905e-dad87871397d"], { + "id": "4cccc72a-0bd0-433a-905e-dad87871397d", + "name": "Roc-A-Fella Records", + "type": "Original Production", + }) diff --git a/brainzutils/musicbrainz_db/tests/test_place.py b/brainzutils/musicbrainz_db/tests/test_place.py new file mode 100644 index 0000000..40a83f1 --- /dev/null +++ b/brainzutils/musicbrainz_db/tests/test_place.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +from unittest import TestCase +from mock import MagicMock +from brainzutils.musicbrainz_db import place as mb_place +from brainzutils.musicbrainz_db.test_data import place_suisto, place_verkatehdas + + +class PlaceTestCase(TestCase): + + def setUp(self): + mb_place.mb_session = MagicMock() + self.mock_db = mb_place.mb_session.return_value.__enter__.return_value + self.place_query = self.mock_db.query.return_value.options.return_value.options.return_value.filter.return_value.all + + def test_get_by_id(self): + self.place_query.return_value = [place_suisto] + place = mb_place.get_place_by_id('d71ffe38-5eaf-426b-9a2e-e1f21bc84609') + self.assertEqual(place['name'], 'Suisto') + self.assertEqual(place['type'], 'Venue') + self.assertDictEqual(place['coordinates'], { + 'latitude': 60.997758, + 'longitude': 24.477142 + }) + self.assertDictEqual(place['area'], { + 'id': '4479c385-74d8-4a2b-bdab-f48d1e6969ba', + 'name': 'Hämeenlinna', + }) + + def test_fetch_multiple_places(self): + self.place_query.return_value = [place_suisto, place_verkatehdas] + places = mb_place.fetch_multiple_places(['f9587914-8505-4bd1-833b-16a3100a4948', 'd71ffe38-5eaf-426b-9a2e-e1f21bc84609']) + self.assertEqual(places['d71ffe38-5eaf-426b-9a2e-e1f21bc84609']['name'], 'Suisto') + self.assertEqual(places['f9587914-8505-4bd1-833b-16a3100a4948']['name'], 'Verkatehdas') diff --git a/brainzutils/musicbrainz_db/tests/test_recording.py b/brainzutils/musicbrainz_db/tests/test_recording.py index 5584a8f..092c15d 100644 --- a/brainzutils/musicbrainz_db/tests/test_recording.py +++ b/brainzutils/musicbrainz_db/tests/test_recording.py @@ -39,14 +39,14 @@ def test_get_recording_by_mbid(self): } ) - def test_get_many_recordings_by_mbid(self): + def test_fetch_multiple_recordings(self): """ Tests if appropriate recordings are returned for a given list of MBIDs. """ self.recording_query.return_value = [recording_numb_encore_explicit, recording_numb_encore_instrumental] mbids = ['daccb724-8023-432a-854c-e0accb6c8678', '965b75df-397d-4395-aac8-de11854c4630'] - recordings = mb_recording.get_many_recordings_by_mbid(mbids, includes=['artists']) + recordings = mb_recording.fetch_multiple_recordings(mbids, includes=['artists']) self.assertDictEqual(recordings, { diff --git a/brainzutils/musicbrainz_db/tests/test_release.py b/brainzutils/musicbrainz_db/tests/test_release.py index 8f2baf0..c3df89c 100644 --- a/brainzutils/musicbrainz_db/tests/test_release.py +++ b/brainzutils/musicbrainz_db/tests/test_release.py @@ -22,7 +22,10 @@ def setUp(self): def test_get_by_id(self): self.release_query.return_value = [release_numb_encore] - release = mb_release.get_release_by_id('16bee711-d7ce-48b0-adf4-51f124bcc0df') + release = mb_release.get_release_by_id( + '16bee711-d7ce-48b0-adf4-51f124bcc0df', + includes=['media', 'release-groups'], + ) self.assertEqual(release["name"], "Numb/Encore") self.assertEqual(len(release["medium-list"][0]["track-list"]), 2) self.assertDictEqual(release["medium-list"][0]["track-list"][0], { diff --git a/brainzutils/musicbrainz_db/tests/test_release_group.py b/brainzutils/musicbrainz_db/tests/test_release_group.py new file mode 100644 index 0000000..a7b16ec --- /dev/null +++ b/brainzutils/musicbrainz_db/tests/test_release_group.py @@ -0,0 +1,79 @@ +from unittest import TestCase +from mock import MagicMock +from brainzutils.musicbrainz_db import release_group as mb_release_group +from brainzutils.musicbrainz_db.test_data import releasegroup_numb_encore, releasegroup_collision_course + + +class ReleaseGroupTestCase(TestCase): + + def setUp(self): + mb_release_group.mb_session = MagicMock() + self.mock_db = mb_release_group.mb_session.return_value.__enter__.return_value + # Mock sql query for fetching release groups and alter the return value to return SQLAlchemy objects. + self._release_group_query = self.mock_db.query.return_value.options.return_value.options.return_value + self._release_group_query_with_artists = self._release_group_query.options.return_value.options.return_value.\ + options.return_value + self.release_group_query = self._release_group_query.filter.return_value.all + self.release_group_query_with_artists = self._release_group_query_with_artists.filter.return_value.all + + def test_get_by_id(self): + self.release_group_query_with_artists.return_value = [releasegroup_numb_encore] + release_group = mb_release_group.get_release_group_by_id( + '7c1014eb-454c-3867-8854-3c95d265f8de', + includes=['artists', 'releases', 'release-group-rels', 'url-rels', 'tags'] + ) + + self.assertEqual(release_group['id'], '7c1014eb-454c-3867-8854-3c95d265f8de') + self.assertEqual(release_group['title'], 'Numb/Encore') + # Check if multiple artists are properly fetched + self.assertEqual(release_group['artist-credit-phrase'], 'Jay-Z/Linkin Park') + self.assertDictEqual(release_group['artist-credit'][0], { + 'name': 'Jay-Z', + 'artist': { + 'id': 'f82bcf78-5b69-4622-a5ef-73800768d9ac', + 'name': 'JAY Z', + 'sort_name': 'JAY Z' + }, + 'join_phrase': '/', + }) + self.assertDictEqual(release_group['artist-credit'][1], { + 'name': 'Linkin Park', + 'artist': { + 'id': 'f59c5520-5f46-4d2c-b2c4-822eabf53419', + 'name': 'Linkin Park', + 'sort_name': 'Linkin Park', + }, + }) + + def test_fetch_release_groups(self): + self.release_group_query.return_value = [releasegroup_numb_encore, releasegroup_collision_course] + release_groups = mb_release_group.fetch_multiple_release_groups( + mbids=['8ef859e3-feb2-4dd1-93da-22b91280d768', '7c1014eb-454c-3867-8854-3c95d265f8de'], + ) + self.assertEqual(len(release_groups), 2) + self.assertEqual(release_groups['7c1014eb-454c-3867-8854-3c95d265f8de']['title'], 'Numb/Encore') + self.assertEqual(release_groups['8ef859e3-feb2-4dd1-93da-22b91280d768']['title'], 'Collision Course') + + def test_fetch_get_release_groups_for_artist(self): + mb_release_group._get_release_groups_for_artist_query = MagicMock() + mock_query = mb_release_group._get_release_groups_for_artist_query.return_value + mock_query.count.return_value = 2 + mock_query.order_by.return_value.limit.return_value.offset.\ + return_value.all.return_value = [releasegroup_collision_course, releasegroup_numb_encore] + release_groups = mb_release_group.get_release_groups_for_artist( + artist_id='f59c5520-5f46-4d2c-b2c4-822eabf53419', + release_types=['Single', 'EP'], + ) + self.assertListEqual(release_groups[0], [ + { + 'id': '8ef859e3-feb2-4dd1-93da-22b91280d768', + 'title': 'Collision Course', + 'first-release-year': 2004, + }, + { + 'id': '7c1014eb-454c-3867-8854-3c95d265f8de', + 'title': 'Numb/Encore', + 'first-release-year': 2004, + } + ]) + self.assertEqual(release_groups[1], 2) diff --git a/brainzutils/musicbrainz_db/tests/test_work.py b/brainzutils/musicbrainz_db/tests/test_work.py new file mode 100644 index 0000000..5c03efb --- /dev/null +++ b/brainzutils/musicbrainz_db/tests/test_work.py @@ -0,0 +1,38 @@ +from unittest import TestCase +from mock import MagicMock +from brainzutils.musicbrainz_db.test_data import work_a_lot, work_aquemini +from brainzutils.musicbrainz_db import work as mb_work + + +class WorkTestCase(TestCase): + + def setUp(self): + mb_work.mb_session = MagicMock() + self.mock_db = mb_work.mb_session.return_value.__enter__.return_value + self.work_query = self.mock_db.query.return_value.options.return_value.filter.return_value.all + + def test_get_work_by_id(self): + self.work_query.return_value = [work_a_lot] + work = mb_work.get_work_by_id('54ce5e07-2aca-4578-83d8-5a41a7b2f434') + self.assertDictEqual(work, { + "id": "54ce5e07-2aca-4578-83d8-5a41a7b2f434", + "name": "a lot", + "type": "Song", + }) + + def test_fetch_multiple_works(self): + self.work_query.return_value = [work_a_lot, work_aquemini] + works = mb_work.fetch_multiple_works([ + '54ce5e07-2aca-4578-83d8-5a41a7b2f434', + '757504fb-a130-4b84-9eb5-1b37164f12dd' + ]) + self.assertDictEqual(works["54ce5e07-2aca-4578-83d8-5a41a7b2f434"], { + "id": "54ce5e07-2aca-4578-83d8-5a41a7b2f434", + "name": "a lot", + "type": "Song", + }) + self.assertDictEqual(works["757504fb-a130-4b84-9eb5-1b37164f12dd"], { + "id": "757504fb-a130-4b84-9eb5-1b37164f12dd", + "name": "Aquemini", + "type": "Song", + }) diff --git a/brainzutils/musicbrainz_db/utils.py b/brainzutils/musicbrainz_db/utils.py index 47ab888..54ff5eb 100644 --- a/brainzutils/musicbrainz_db/utils.py +++ b/brainzutils/musicbrainz_db/utils.py @@ -9,9 +9,11 @@ 'release_group': models.ReleaseGroup, 'release': models.Release, 'event': models.Event, + 'label': models.Label, 'series': models.Series, 'url': models.URL, 'recording': models.Recording, + 'work': models.Work, 'editor': models.Editor, } @@ -23,7 +25,9 @@ 'release': models.ReleaseGIDRedirect, 'release_group': models.ReleaseGroupGIDRedirect, 'event': models.EventGIDRedirect, + 'label': models.LabelGIDRedirect, 'recording': models.RecordingGIDRedirect, + 'work': models.WorkGIDRedirect, } diff --git a/brainzutils/musicbrainz_db/work.py b/brainzutils/musicbrainz_db/work.py new file mode 100644 index 0000000..a347a54 --- /dev/null +++ b/brainzutils/musicbrainz_db/work.py @@ -0,0 +1,71 @@ +from collections import defaultdict +from mbdata import models +from sqlalchemy.orm import joinedload +from brainzutils.musicbrainz_db import mb_session +from brainzutils.musicbrainz_db.utils import get_entities_by_gids +from brainzutils.musicbrainz_db.includes import check_includes +from brainzutils.musicbrainz_db.serialize import serialize_works +from brainzutils.musicbrainz_db.helpers import get_relationship_info + + +def get_work_by_id(mbid, includes=None): + """Get work with the MusicBrainz ID. + + Args: + mbid (uuid): MBID(gid) of the work. + Returns: + Dictionary containing the work information. + """ + if includes is None: + includes = [] + + return fetch_multiple_works( + [mbid], + includes=includes, + ).get(mbid) + + +def fetch_multiple_works(mbids, includes=None): + """Get info related to multiple works using their MusicBrainz IDs. + + Args: + mbids (list): List of MBIDs of works. + includes (list): List of information to be included. + + Returns: + Dictionary containing info of multiple works keyed by their mbid. + """ + if includes is None: + includes = [] + includes_data = defaultdict(dict) + check_includes('work', includes) + with mb_session() as db: + query = db.query(models.Work).\ + options(joinedload("type")) + works = get_entities_by_gids( + query=query, + entity_type='work', + mbids=mbids, + ) + work_ids = [work.id for work in works.values()] + + if 'artist-rels' in includes: + get_relationship_info( + db=db, + target_type='artist', + source_type='work', + source_entity_ids=work_ids, + includes_data=includes_data, + ) + + if 'recording-rels' in includes: + get_relationship_info( + db=db, + target_type='recording', + source_type='work', + source_entity_ids=work_ids, + includes_data=includes_data, + ) + for work in works.values(): + includes_data[work.id]['type'] = work.type + return {str(mbid): serialize_works(works[mbid], includes_data[works[mbid].id]) for mbid in mbids} From 75e7e4690f4094300a9fee053e0d3f7727d4e59f Mon Sep 17 00:00:00 2001 From: spellew Date: Mon, 10 Jun 2019 18:34:25 -0400 Subject: [PATCH 2/4] Testing label and recording retrieval --- brainzutils/musicbrainz_db/label.py | 4 ++-- brainzutils/musicbrainz_db/recording.py | 3 +++ brainzutils/musicbrainz_db/serialize.py | 6 ++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/brainzutils/musicbrainz_db/label.py b/brainzutils/musicbrainz_db/label.py index a43c0cc..fec941e 100644 --- a/brainzutils/musicbrainz_db/label.py +++ b/brainzutils/musicbrainz_db/label.py @@ -40,8 +40,8 @@ def fetch_multiple_labels(mbids, includes=None): check_includes('label', includes) with mb_session() as db: query = db.query(models.Label).\ - options(joinedload("type")). - + options(joinedload("type")).\ + options(joinedload("area")) labels = get_entities_by_gids( query=query, entity_type='label', diff --git a/brainzutils/musicbrainz_db/recording.py b/brainzutils/musicbrainz_db/recording.py index 6d03a04..108544e 100644 --- a/brainzutils/musicbrainz_db/recording.py +++ b/brainzutils/musicbrainz_db/recording.py @@ -108,6 +108,9 @@ def fetch_multiple_recordings(mbids, includes=None): includes_data=includes_data, ) + print("includes") + print(includes) + serial_recordings = {str(mbid): serialize_recording(recordings[mbid], includes_data[recordings[mbid].id]) for mbid in mbids} return serial_recordings diff --git a/brainzutils/musicbrainz_db/serialize.py b/brainzutils/musicbrainz_db/serialize.py index 2201f4b..6b966c6 100644 --- a/brainzutils/musicbrainz_db/serialize.py +++ b/brainzutils/musicbrainz_db/serialize.py @@ -68,6 +68,10 @@ def serialize_artist_credit(artist_credit): def serialize_recording(recording, includes=None): """Convert recording objects into dictionary.""" + print("recording") + print(recording) + print("includes") + print(includes) if includes is None: includes = {} data = { @@ -123,6 +127,8 @@ def serialize_places(place, includes=None): def serialize_labels(label, includes=None): + print("label") + print(label) if includes is None: includes = {} data = { From 9e2d53a5379ff8ad196685112384a3b86489fbfe Mon Sep 17 00:00:00 2001 From: spellew Date: Mon, 10 Jun 2019 19:39:27 -0400 Subject: [PATCH 3/4] Joined area to label query --- brainzutils/musicbrainz_db/includes.py | 2 +- brainzutils/musicbrainz_db/label.py | 2 ++ brainzutils/musicbrainz_db/serialize.py | 9 +++------ brainzutils/musicbrainz_db/test_data.py | 10 ++++++++++ brainzutils/musicbrainz_db/tests/test_label.py | 5 ++++- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/brainzutils/musicbrainz_db/includes.py b/brainzutils/musicbrainz_db/includes.py index 12a8c91..6839140 100644 --- a/brainzutils/musicbrainz_db/includes.py +++ b/brainzutils/musicbrainz_db/includes.py @@ -31,7 +31,7 @@ "artists", "labels", "recordings", "release-groups", "media", "annotation", "aliases" ] + TAG_INCLUDES + RELATION_INCLUDES, 'artist': ["recordings", "releases", "media", "aliases", "annotation"] + RELATION_INCLUDES + TAG_INCLUDES, - 'label': ["aliases", "annotation"] + RELATION_INCLUDES + TAG_INCLUDES, + 'label': ["area", "aliases", "annotation"] + RELATION_INCLUDES + TAG_INCLUDES, 'work': ["artists", "recordings", "aliases", "annotation"] + RELATION_INCLUDES + TAG_INCLUDES, 'editor': [], # TODO: List includes here (BU-18) } diff --git a/brainzutils/musicbrainz_db/label.py b/brainzutils/musicbrainz_db/label.py index fec941e..dd5ceb7 100644 --- a/brainzutils/musicbrainz_db/label.py +++ b/brainzutils/musicbrainz_db/label.py @@ -69,4 +69,6 @@ def fetch_multiple_labels(mbids, includes=None): for label in labels.values(): includes_data[label.id]['type'] = label.type + includes_data[label.id]['area'] = label.area + return {str(mbid): serialize_labels(labels[mbid], includes_data[labels[mbid].id]) for mbid in mbids} diff --git a/brainzutils/musicbrainz_db/serialize.py b/brainzutils/musicbrainz_db/serialize.py index 6b966c6..05ecedf 100644 --- a/brainzutils/musicbrainz_db/serialize.py +++ b/brainzutils/musicbrainz_db/serialize.py @@ -68,10 +68,6 @@ def serialize_artist_credit(artist_credit): def serialize_recording(recording, includes=None): """Convert recording objects into dictionary.""" - print("recording") - print(recording) - print("includes") - print(includes) if includes is None: includes = {} data = { @@ -127,8 +123,6 @@ def serialize_places(place, includes=None): def serialize_labels(label, includes=None): - print("label") - print(label) if includes is None: includes = {} data = { @@ -142,6 +136,9 @@ def serialize_labels(label, includes=None): if 'type' in includes and includes['type']: data['type'] = includes['type'].name + if 'area' in includes and includes['area']: + data['area'] = includes['area'].name + if 'relationship_objs' in includes: serialize_relationships(data, label, includes['relationship_objs']) diff --git a/brainzutils/musicbrainz_db/test_data.py b/brainzutils/musicbrainz_db/test_data.py index ce272c4..fefb3e1 100644 --- a/brainzutils/musicbrainz_db/test_data.py +++ b/brainzutils/musicbrainz_db/test_data.py @@ -32,6 +32,14 @@ WorkType ) +# Area (489ce91b-6658-3307-9877-795b68554c98) +area_united_states = Area() +area_united_states.id = 222 +area_united_states.gid = '489ce91b-6658-3307-9877-795b68554c98' +area_united_states.name = 'United States' +area_united_states.ended = False +area_united_states.comment = '' + # Label (1aed8c3b-8e1e-46f8-b558-06357ff5f298) labeltype_imprint = LabelType() labeltype_imprint.id = 9 @@ -47,6 +55,7 @@ label_dreamville.ended = False label_dreamville.label_code = None label_dreamville.begin_date_year = 2007 +label_dreamville.area = area_united_states label_dreamville.type = labeltype_imprint # Label (4cccc72a-0bd0-433a-905e-dad87871397d) @@ -64,6 +73,7 @@ label_roc_a_fella.ended = False label_roc_a_fella.label_code = None label_roc_a_fella.begin_date_year = 1996 +label_roc_a_fella.area = area_united_states label_roc_a_fella.type = labeltype_original_production # Place (d71ffe38-5eaf-426b-9a2e-e1f21bc84609) with url-rels, place-rels diff --git a/brainzutils/musicbrainz_db/tests/test_label.py b/brainzutils/musicbrainz_db/tests/test_label.py index 7f6b2eb..8b6f7d1 100644 --- a/brainzutils/musicbrainz_db/tests/test_label.py +++ b/brainzutils/musicbrainz_db/tests/test_label.py @@ -9,7 +9,7 @@ class LabelTestCase(TestCase): def setUp(self): mb_label.mb_session = MagicMock() self.mock_db = mb_label.mb_session.return_value.__enter__.return_value - self.label_query = self.mock_db.query.return_value.options.return_value.filter.return_value.all + self.label_query = self.mock_db.query.return_value.options.return_value.options.return_value.filter.return_value.all def test_get_label_by_id(self): self.label_query.return_value = [label_dreamville] @@ -18,6 +18,7 @@ def test_get_label_by_id(self): "id": "1aed8c3b-8e1e-46f8-b558-06357ff5f298", "name": "Dreamville", "type": "Imprint", + "area": "United States", }) def test_fetch_multiple_labels(self): @@ -30,9 +31,11 @@ def test_fetch_multiple_labels(self): "id": "1aed8c3b-8e1e-46f8-b558-06357ff5f298", "name": "Dreamville", "type": "Imprint", + "area": "United States", }) self.assertDictEqual(labels["4cccc72a-0bd0-433a-905e-dad87871397d"], { "id": "4cccc72a-0bd0-433a-905e-dad87871397d", "name": "Roc-A-Fella Records", "type": "Original Production", + "area": "United States", }) From 4b306507d701562f73bec5e2bb6f3be71127ad13 Mon Sep 17 00:00:00 2001 From: spellew Date: Mon, 10 Jun 2019 20:47:31 -0400 Subject: [PATCH 4/4] Removed debugging --- brainzutils/musicbrainz_db/recording.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/brainzutils/musicbrainz_db/recording.py b/brainzutils/musicbrainz_db/recording.py index 108544e..6d03a04 100644 --- a/brainzutils/musicbrainz_db/recording.py +++ b/brainzutils/musicbrainz_db/recording.py @@ -108,9 +108,6 @@ def fetch_multiple_recordings(mbids, includes=None): includes_data=includes_data, ) - print("includes") - print(includes) - serial_recordings = {str(mbid): serialize_recording(recordings[mbid], includes_data[recordings[mbid].id]) for mbid in mbids} return serial_recordings