From 862c25dd35fe81bca8bf74da281ceeabda834fbd Mon Sep 17 00:00:00 2001 From: Hellow Date: Sat, 18 Mar 2023 12:36:53 +0100 Subject: [PATCH] refactored merging function to take default values other than None into account parents.py --- src/music_kraken/objects/formatted_text.py | 19 ++++++- src/music_kraken/objects/lyrics.py | 12 ++-- src/music_kraken/objects/metadata.py | 2 + src/music_kraken/objects/parents.py | 23 ++++---- src/music_kraken/objects/song.py | 65 ++++++++++++++++++---- src/music_kraken/objects/source.py | 6 +- src/music_kraken/objects/target.py | 6 +- src/musify_search.py | 3 +- 8 files changed, 103 insertions(+), 33 deletions(-) diff --git a/src/music_kraken/objects/formatted_text.py b/src/music_kraken/objects/formatted_text.py index 238cc2c..3027319 100644 --- a/src/music_kraken/objects/formatted_text.py +++ b/src/music_kraken/objects/formatted_text.py @@ -43,19 +43,32 @@ class FormattedText: def get_markdown(self) -> str: if self.doc is None: - return None + return "" return pandoc.write(self.doc, format="markdown").strip() def get_html(self) -> str: if self.doc is None: - return None + return "" return pandoc.write(self.doc, format="html").strip() def get_plaintext(self) -> str: if self.doc is None: - return None + return "" return pandoc.write(self.doc, format="plain").strip() + @property + def is_empty(self) -> bool: + return self.doc is None + + def __eq__(self, other) -> False: + if type(other) != type(self): + return False + if self.is_empty and other.is_empty: + return True + + return self.doc == other.doc + + plaintext = property(fget=get_plaintext, fset=set_plaintext) markdown = property(fget=get_markdown, fset=set_markdown) diff --git a/src/music_kraken/objects/lyrics.py b/src/music_kraken/objects/lyrics.py index dc668ed..d2ba425 100644 --- a/src/music_kraken/objects/lyrics.py +++ b/src/music_kraken/objects/lyrics.py @@ -1,16 +1,18 @@ from typing import List - +from collections import defaultdict import pycountry from .parents import DatabaseObject from .source import Source, SourceCollection -from .metadata import Metadata from .formatted_text import FormattedText class Lyrics(DatabaseObject): COLLECTION_ATTRIBUTES = ("source_collection",) - SIMPLE_ATTRIBUTES = ("text", "language") + SIMPLE_ATTRIBUTES = { + "text": FormattedText(), + "language": None + } def __init__( self, @@ -21,9 +23,9 @@ class Lyrics(DatabaseObject): source_list: List[Source] = None, **kwargs ) -> None: - DatabaseObject.__init__(self, _id=_id, dynamic=dynamic) + DatabaseObject.__init__(self, _id=_id, dynamic=dynamic, **kwargs) - self.text: FormattedText = text + self.text: FormattedText = text or FormattedText() self.language: pycountry.Languages = language self.source_collection: SourceCollection = SourceCollection(source_list) diff --git a/src/music_kraken/objects/metadata.py b/src/music_kraken/objects/metadata.py index 1c7b294..404af9c 100644 --- a/src/music_kraken/objects/metadata.py +++ b/src/music_kraken/objects/metadata.py @@ -154,6 +154,8 @@ class ID3Timestamp: return self.date_obj >= other.date_obj def __eq__(self, other): + if type(other) != type(self): + return False return self.date_obj == other.date_obj def get_time_format(self) -> str: diff --git a/src/music_kraken/objects/parents.py b/src/music_kraken/objects/parents.py index c9993b7..855ba71 100644 --- a/src/music_kraken/objects/parents.py +++ b/src/music_kraken/objects/parents.py @@ -11,11 +11,11 @@ from .option import Options class DatabaseObject: COLLECTION_ATTRIBUTES: tuple = tuple() - SIMPLE_ATTRIBUTES: tuple = tuple() - + SIMPLE_ATTRIBUTES: dict = dict() + def __init__(self, _id: str = None, dynamic: bool = False, **kwargs) -> None: self.automatic_id: bool = False - + if _id is None and not dynamic: """ generates a random UUID @@ -46,7 +46,7 @@ class DatabaseObject: return True return False - + @property def indexing_values(self) -> List[Tuple[str, object]]: """ @@ -56,9 +56,9 @@ class DatabaseObject: Returns: List[Tuple[str, object]]: the first element in the tuple is the name of the attribute, the second the value. """ - + return list() - + def merge(self, other, override: bool = False): if not isinstance(other, type(self)): LOGGER.warning(f"can't merge \"{type(other)}\" into \"{type(self)}\"") @@ -67,14 +67,13 @@ class DatabaseObject: for collection in type(self).COLLECTION_ATTRIBUTES: getattr(self, collection).extend(getattr(other, collection)) - for simple_attribute in type(self).SIMPLE_ATTRIBUTES: - if getattr(other, simple_attribute) is None: + for simple_attribute, default_value in type(self).SIMPLE_ATTRIBUTES.items(): + if getattr(other, simple_attribute) == default_value: continue - if override or getattr(self, simple_attribute) is None: + if override or getattr(self, simple_attribute) == default_value: setattr(self, simple_attribute, getattr(other, simple_attribute)) - @property def metadata(self) -> Metadata: return Metadata() @@ -86,7 +85,7 @@ class DatabaseObject: @property def option_string(self) -> str: return self.__repr__() - + def compile(self) -> bool: """ compiles the recursive structures, @@ -111,7 +110,7 @@ class MainObject(DatabaseObject): It has all the functionality of the "DatabaseObject" (it inherits from said class) but also some added functions as well. """ - + def __init__(self, _id: str = None, dynamic: bool = False, **kwargs): DatabaseObject.__init__(self, _id=_id, dynamic=dynamic, **kwargs) diff --git a/src/music_kraken/objects/song.py b/src/music_kraken/objects/song.py index 252678d..4169994 100644 --- a/src/music_kraken/objects/song.py +++ b/src/music_kraken/objects/song.py @@ -1,6 +1,7 @@ import os from typing import List, Optional, Dict, Tuple import pycountry +from collections import defaultdict from .metadata import ( Mapping as id3Mapping, @@ -46,7 +47,15 @@ class Song(MainObject): COLLECTION_ATTRIBUTES = ( "lyrics_collection", "album_collection", "main_artist_collection", "feature_artist_collection", "source_collection") - SIMPLE_ATTRIBUTES = ("title", "unified_title", "isrc", "length", "tracksort", "genre") + SIMPLE_ATTRIBUTES = { + "title": None, + "unified_title": None, + "isrc": None, + "length": None, + "tracksort": 0, + "genre": None, + "notes": FormattedText() + } def __init__( self, @@ -64,17 +73,21 @@ class Song(MainObject): album_list: List['Album'] = None, main_artist_list: List['Artist'] = None, feature_artist_list: List['Artist'] = None, + notes: FormattedText = None, **kwargs ) -> None: MainObject.__init__(self, _id=_id, dynamic=dynamic, **kwargs) # attributes self.title: str = title - self.unified_title: str = unified_title or unify(title) + self.unified_title: str = unified_title + if unified_title is None and title is not None: + self.unified_title = unify(title) self.isrc: str = isrc self.length: int = length self.tracksort: int = tracksort or 0 self.genre: str = genre + self.notes: FormattedText = notes or FormattedText() self.source_collection: SourceCollection = SourceCollection(source_list) self.target_collection: Collection = Collection(data=target_list, element_type=Target) @@ -181,7 +194,17 @@ All objects dependent on Album class Album(MainObject): COLLECTION_ATTRIBUTES = ("label_collection", "artist_collection", "song_collection") - SIMPLE_ATTRIBUTES = ("title", "album_status", "album_type", "language", "date", "barcode", "albumsort") + SIMPLE_ATTRIBUTES = { + "title": None, + "unified_title": None, + "album_status": None, + "album_type": AlbumType.OTHER, + "language": None, + "date": ID3Timestamp(), + "barcode": None, + "albumsort": None, + "notes": FormattedText() + } def __init__( self, @@ -199,15 +222,18 @@ class Album(MainObject): album_status: AlbumStatus = None, album_type: AlbumType = None, label_list: List['Label'] = None, + notes: FormattedText = None, **kwargs ) -> None: MainObject.__init__(self, _id=_id, dynamic=dynamic, **kwargs) self.title: str = title - self.unified_title: str = unified_title or unify(self.title) + self.unified_title: str = unified_title + if unified_title is None and title is not None: + self.unified_title = unify(title) self.album_status: AlbumStatus = album_status - self.album_type: AlbumType = album_type + self.album_type: AlbumType = album_type or AlbumType.OTHER self.language: pycountry.Languages = language self.date: ID3Timestamp = date or ID3Timestamp() @@ -223,6 +249,7 @@ class Album(MainObject): to set albumsort with help of the release year """ self.albumsort: Optional[int] = albumsort + self.notes = notes or FormattedText() self.source_collection: SourceCollection = SourceCollection(source_list) self.song_collection: Collection = Collection(data=song_list, element_type=Song) @@ -230,7 +257,7 @@ class Album(MainObject): self.label_collection: Collection = Collection(data=label_list, element_type=Label) def compile(self): - song: "Song" + song: Song for song in self.song_collection: if song.album_collection.insecure_append(self): song.compile() @@ -351,7 +378,15 @@ All objects dependent on Artist class Artist(MainObject): COLLECTION_ATTRIBUTES = ("feature_song_collection", "main_album_collection", "label_collection") - SIMPLE_ATTRIBUTES = ("name", "name", "country", "formed_in", "notes", "lyrical_themes", "general_genre") + SIMPLE_ATTRIBUTES = { + "name": None, + "unified_name": None, + "country": None, + "formed_in": ID3Timestamp(), + "notes": FormattedText(), + "lyrical_themes": [], + "general_genre": "" + } def __init__( self, @@ -373,7 +408,9 @@ class Artist(MainObject): MainObject.__init__(self, _id=_id, dynamic=dynamic, **kwargs) self.name: str = name - self.unified_name: str = unified_name or unify(self.name) + self.unified_name: str = unified_name + if unified_name is None and name is not None: + self.unified_name = unify(name) """ TODO implement album type and notes @@ -512,7 +549,11 @@ Label class Label(MainObject): COLLECTION_ATTRIBUTES = ("album_collection", "current_artist_collection") - SIMPLE_ATTRIBUTES = ("name",) + SIMPLE_ATTRIBUTES = { + "name": None, + "unified_name": None, + "notes": FormattedText() + } def __init__( self, @@ -520,6 +561,7 @@ class Label(MainObject): dynamic: bool = False, name: str = None, unified_name: str = None, + notes: FormattedText = None, album_list: List[Album] = None, current_artist_list: List[Artist] = None, source_list: List[Source] = None, @@ -528,7 +570,10 @@ class Label(MainObject): MainObject.__init__(self, _id=_id, dynamic=dynamic, **kwargs) self.name: str = name - self.unified_name: str = unified_name or unify(self.name) + self.unified_name: str = unified_name + if unified_name is None and name is not None: + self.unified_name = unify(name) + self.notes = notes or FormattedText() self.source_collection: SourceCollection = SourceCollection(source_list) self.album_collection: Collection = Collection(data=album_list, element_type=Album) diff --git a/src/music_kraken/objects/source.py b/src/music_kraken/objects/source.py index 8fe03fc..7213575 100644 --- a/src/music_kraken/objects/source.py +++ b/src/music_kraken/objects/source.py @@ -56,7 +56,11 @@ class Source(DatabaseObject): ``` """ COLLECTION_ATTRIBUTES = tuple() - SIMPLE_ATTRIBUTES = ("type_enum", "page_enum", "url") + SIMPLE_ATTRIBUTES = { + "type_enum": None, + "page_enum": None, + "url": None + } def __init__(self, page_enum: SourcePages, url: str, id_: str = None, type_enum=None) -> None: DatabaseObject.__init__(self, id_=id_) diff --git a/src/music_kraken/objects/target.py b/src/music_kraken/objects/target.py index 895e367..3766eb0 100644 --- a/src/music_kraken/objects/target.py +++ b/src/music_kraken/objects/target.py @@ -1,5 +1,6 @@ from typing import Optional, List, Tuple from pathlib import Path +from collections import defaultdict from ..utils import shared from .parents import DatabaseObject @@ -14,7 +15,10 @@ class Target(DatabaseObject): ``` """ - SIMPLE_ATTRIBUTES = ("_file", "_path") + SIMPLE_ATTRIBUTES = { + "_file": None, + "_path": None + } COLLECTION_ATTRIBUTES = tuple() def __init__( diff --git a/src/musify_search.py b/src/musify_search.py index a6ed8ef..a95e172 100644 --- a/src/musify_search.py +++ b/src/musify_search.py @@ -12,9 +12,10 @@ def fetch_artist(): name="Ghost Bath", source_list=[objects.Source(objects.SourcePages.MUSIFY, "https://musify.club/artist/psychonaut-4-83193")] ) - + artist = Musify.fetch_details(artist) print(artist.options) + if __name__ == "__main__": fetch_artist()