diff --git a/src/create_custom_objects.py b/src/create_custom_objects.py index a29e5a8..3d954c2 100644 --- a/src/create_custom_objects.py +++ b/src/create_custom_objects.py @@ -9,7 +9,7 @@ from music_kraken.objects import ( from music_kraken.objects.collection import Collection from music_kraken.utils.enums import SourcePages -""" + only_smile = Artist( name="Only Smile", source_list=[Source(SourcePages.BANDCAMP, "https://onlysmile.bandcamp.com/")], @@ -103,7 +103,7 @@ for _id, _object in objects_by_id.items(): print(_id, _object, sep=": ") print(only_smile) -""" + c = Collection([Song(title="hi"), Song(title="hi2"), Song(title="hi3")]) c1 = Collection([Song(title="he"), Song(title="hi5")]) @@ -139,7 +139,7 @@ print(other_song) print() print(c.data, len(c)) print(c1.data) -print([obj.genre for obj in c.data]) +print([(obj.genre or "various") + ":" + obj.title for obj in c.data]) print() print("c: ", c) diff --git a/src/music_kraken/objects/collection.py b/src/music_kraken/objects/collection.py index c73ecdb..372de80 100644 --- a/src/music_kraken/objects/collection.py +++ b/src/music_kraken/objects/collection.py @@ -72,16 +72,52 @@ class Collection(Generic[T], metaclass=MetaClass): if value in self._indexed_values[name]: return True return False + + def _get_root_collections(self) -> List["Collection"]: + if not len(self.upper_collections): + return [self] + + root_collections = [] + for upper_collection in self.upper_collections: + root_collections.extend(upper_collection._get_root_collections()) + return root_collections + + @property + def _is_root(self) -> bool: + return len(self.upper_collections) <= 0 + + def _contained_in_sub(self, __object: T, break_at_first: bool = True) -> List["Collection"]: + results = [] - def _contained_in(self, __object: T) -> Optional["Collection"]: if self._contained_in_self(__object): - return self + return [self] for collection in self.contained_collections: - if collection._contained_in_self(__object): - return collection + results.extend(collection._contained_in_sub(__object, break_at_first=break_at_first)) + if break_at_first: + return results + + return results + + def _get_parents_of_multiple_contained_children(self, __object: T): + results = [] + if len(self.contained_collections) < 2 or self._contained_in_self(__object): + return results + + count = 0 + + for collection in self.contained_collections: + sub_results = collection._get_parents_of_multiple_contained_children(__object) - return None + if len(sub_results) > 0: + count += 1 + results.extend(sub_results) + + if count >= 2: + results.append(self) + + return results + def _merge_in_self(self, __object: T): """ @@ -110,23 +146,31 @@ class Collection(Generic[T], metaclass=MetaClass): self._map_element(existing_object) def contains(self, __object: T) -> bool: - return self._contained_in(__object) is not None - + return len(self._contained_in_sub(__object)) > 0 def _append(self, __object: T): self._map_element(__object) self._data.append(__object) - def append(self, __object: Optional[T]): + def append(self, __object: Optional[T], already_is_parent: bool = False): if __object is None: return - exists_in_collection = self._contained_in(__object) + exists_in_collection = self._contained_in_sub(__object) + if len(exists_in_collection) and self is exists_in_collection[0]: + # assuming that the object already is contained in the correct collections + if not already_is_parent: + self._merge_in_self(__object) + return - if exists_in_collection is None: + if not len(exists_in_collection): self._append(__object) else: - exists_in_collection._merge_in_self(__object) + exists_in_collection[0]._merge_in_self(__object) + + if not already_is_parent or not self._is_root: + for parent_collection in self._get_parents_of_multiple_contained_children(__object): + parent_collection.append(__object, already_is_parent=True) def extend(self, __iterable: Optional[Iterable[T]]): if __iterable is None: @@ -135,6 +179,7 @@ class Collection(Generic[T], metaclass=MetaClass): for __object in __iterable: self.append(__object) + def sync_with_other_collection(self, equal_collection: "Collection"): """ If two collections always need to have the same values, this can be used. diff --git a/src/music_kraken/objects/parents.py b/src/music_kraken/objects/parents.py index 36bb3a7..d6d4a09 100644 --- a/src/music_kraken/objects/parents.py +++ b/src/music_kraken/objects/parents.py @@ -1,3 +1,4 @@ +from __future__ import annotations import random from collections import defaultdict from typing import Optional, Dict, Tuple, List, Type, Generic, TypeVar, Any @@ -94,17 +95,17 @@ class DatabaseObject(metaclass=MetaClass): self.build_version = -1 @property - def upwards_collection(self) -> "Collection": + def upwards_collection(self) -> Collection: for attribute in self._upwards_collection_attributes: yield attribute.get() @property - def downwards_collection(self) -> "Collection": + def downwards_collection(self) -> Collection: for attribute in self._downwards_collection_attributes: yield attribute.get() @property - def all_collections(self) -> "Collection": + def all_collections(self) -> Collection: for attribute in self._collection_attributes: yield attribute.get() diff --git a/src/music_kraken/objects/song.py b/src/music_kraken/objects/song.py index 85464df..d7b1cef 100644 --- a/src/music_kraken/objects/song.py +++ b/src/music_kraken/objects/song.py @@ -594,7 +594,7 @@ class Artist(MainObject): self.unformated_location: Optional[str] = unformated_location self.source_collection: SourceCollection = SourceCollection(source_list) - self.contact_collection: Collection[Label] = Collection(data=contact_list, element_type=Contact) + self.contact_collection: Collection[Label] = Collection(data=contact_list) self.feature_song_collection: Collection[Song] = Collection( data=feature_song_list,