feat: new attribute system

This commit is contained in:
Hellow 2023-09-14 23:35:37 +02:00
parent 33f97662d7
commit ad4328dd11
8 changed files with 158 additions and 36 deletions

View File

@ -19,7 +19,7 @@ Additionally it provides an **Interface** to:
### DatabaseObject.merge()
To merge the data of two instances of the same type, the attributes defined in `DatabaseObject.COLLECTION_ATTRIBUTES` and `SIMPLE_ATTRIBUTES` are used.
To merge the data of two instances of the same type, the attributes defined in `DatabaseObject.COLLECTION_STRING_ATTRIBUTES` and `SIMPLE_STRING_ATTRIBUTES` are used.
The simple attributes just get carried from the other instance, to the self instance.

View File

@ -5,8 +5,8 @@ from .parents import DatabaseObject
class Contact(DatabaseObject):
COLLECTION_ATTRIBUTES = tuple()
SIMPLE_ATTRIBUTES = {
COLLECTION_STRING_ATTRIBUTES = tuple()
SIMPLE_STRING_ATTRIBUTES = {
"contact_method": None,
"value": None,
}

View File

@ -8,8 +8,8 @@ from .formatted_text import FormattedText
class Lyrics(DatabaseObject):
COLLECTION_ATTRIBUTES = ("source_collection",)
SIMPLE_ATTRIBUTES = {
COLLECTION_STRING_ATTRIBUTES = ("source_collection",)
SIMPLE_STRING_ATTRIBUTES = {
"text": FormattedText(),
"language": None
}

View File

@ -1,6 +1,7 @@
import random
from collections import defaultdict
from typing import Optional, Dict, Tuple, List, Type
from typing import Optional, Dict, Tuple, List, Type, Generic, TypeVar, Any
from dataclasses import dataclass
from .metadata import Metadata
from .option import Options
@ -10,15 +11,46 @@ from ..utils.config import main_settings, logging_settings
LOGGER = logging_settings["object_logger"]
T = TypeVar('T')
@dataclass
class StaticAttribute(Generic[T]):
name: str
default_value: Any = None
weight: float = 0
is_simple: bool = True
is_collection: bool = False
is_downwards_collection: bool = False
is_upwards_collection: bool = False
class Attribute(Generic[T]):
def __init__(self, database_object: "DatabaseObject", static_attribute: StaticAttribute) -> None:
self.database_object: DatabaseObject = database_object
self.static_attribute: StaticAttribute = static_attribute
def get(self) -> T:
return self.database_object.__getattribute__(self.name)
def set(self, value: T):
self.database_object.__setattr__(self.name, value)
class DatabaseObject:
COLLECTION_ATTRIBUTES: tuple = tuple()
SIMPLE_ATTRIBUTES: dict = dict()
COLLECTION_STRING_ATTRIBUTES: tuple = tuple()
SIMPLE_STRING_ATTRIBUTES: dict = dict()
# contains all collection attributes, which describe something "smaller"
# e.g. album has songs, but not artist.
DOWNWARDS_COLLECTION_ATTRIBUTES: tuple = tuple()
UPWARDS_COLLECTION_ATTRIBUTES: tuple = tuple()
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES: tuple = tuple()
UPWARDS_COLLECTION_STRING_ATTRIBUTES: tuple = tuple()
STATIC_ATTRIBUTES: List[StaticAttribute] = list()
def __init__(self, _id: int = None, dynamic: bool = False, **kwargs) -> None:
self.automatic_id: bool = False
@ -33,13 +65,43 @@ class DatabaseObject:
self.automatic_id = True
# LOGGER.debug(f"Id for {type(self).__name__} isn't set. Setting to {_id}")
self._attributes: List[Attribute] = []
self._simple_attribute_list: List[Attribute] = []
self._collection_attributes: List[Attribute] = []
self._downwards_collection_attributes: List[Attribute] = []
self._upwards_collection_attributes: List[Attribute] = []
for static_attribute in self.STATIC_ATTRIBUTES:
attribute: Attribute = Attribute(self, static_attribute)
self._attributes.append(attribute)
if static_attribute.is_simple:
self._simple_attribute_list.append(attribute)
else:
if static_attribute.is_collection:
self._collection_attributes.append(attribute)
if static_attribute.is_upwards_collection:
self._upwards_collection_attributes.append(attribute)
if static_attribute.is_downwards_collection:
self._downwards_collection_attributes.append(attribute)
# The id can only be None, if the object is dynamic (self.dynamic = True)
self.id: Optional[int] = _id
self.dynamic = dynamic
self.build_version = -1
@property
def upwards_collection(self) -> "Collection":
for attribute in self._upwards_collection_attributes:
yield attribute.get()
@property
def downwards_collection(self) -> "Collection":
for attribute in self._downwards_collection_attributes:
yield attribute.get()
def __hash__(self):
if self.dynamic:
raise TypeError("Dynamic DatabaseObjects are unhashable.")
@ -89,10 +151,10 @@ class DatabaseObject:
LOGGER.warning(f"can't merge \"{type(other)}\" into \"{type(self)}\"")
return
for collection in type(self).COLLECTION_ATTRIBUTES:
for collection in type(self).COLLECTION_STRING_ATTRIBUTES:
getattr(self, collection).extend(getattr(other, collection))
for simple_attribute, default_value in type(self).SIMPLE_ATTRIBUTES.items():
for simple_attribute, default_value in type(self).SIMPLE_STRING_ATTRIBUTES.items():
if getattr(other, simple_attribute) == default_value:
continue
@ -100,7 +162,7 @@ class DatabaseObject:
setattr(self, simple_attribute, getattr(other, simple_attribute))
def strip_details(self):
for collection in type(self).DOWNWARDS_COLLECTION_ATTRIBUTES:
for collection in type(self).DOWNWARDS_COLLECTION_STRING_ATTRIBUTES:
getattr(self, collection).clear()
@property

View File

@ -15,7 +15,7 @@ from .metadata import (
Metadata
)
from .option import Options
from .parents import MainObject, DatabaseObject
from .parents import MainObject, DatabaseObject, StaticAttribute
from .source import Source, SourceCollection
from .target import Target
from ..utils.string_processing import unify
@ -36,10 +36,10 @@ class Song(MainObject):
tracksort, genre, source_list, target, lyrics_list, album, main_artist_list, and feature_artist_list.
"""
COLLECTION_ATTRIBUTES = (
COLLECTION_STRING_ATTRIBUTES = (
"lyrics_collection", "album_collection", "main_artist_collection", "feature_artist_collection",
"source_collection")
SIMPLE_ATTRIBUTES = {
SIMPLE_STRING_ATTRIBUTES = {
"title": None,
"unified_title": None,
"isrc": None,
@ -49,7 +49,23 @@ class Song(MainObject):
"notes": FormattedText()
}
UPWARDS_COLLECTION_ATTRIBUTES = ("album_collection", "main_artist_collection", "feature_artist_collection")
UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("album_collection", "main_artist_collection", "feature_artist_collection")
STATIC_ATTRIBUTES = [
StaticAttribute(name="title", weight=.5),
StaticAttribute(name="unified_title", weight=.3),
StaticAttribute(name="isrc", weight=1),
StaticAttribute(name="length"),
StaticAttribute(name="tracksort", default_value=0),
StaticAttribute(name="genre"),
StaticAttribute(name="notes", default_value=FormattedText()),
StaticAttribute(name="source_collection", is_collection=True),
StaticAttribute(name="lyrics_collection", is_collection=True),
StaticAttribute(name="album_collection", is_collection=True, is_upwards_collection=True),
StaticAttribute(name="main_artist_collection", is_collection=True, is_upwards_collection=True),
StaticAttribute(name="feature_artist_collection", is_collection=True, is_upwards_collection=True)
]
def __init__(
self,
@ -212,8 +228,8 @@ All objects dependent on Album
class Album(MainObject):
COLLECTION_ATTRIBUTES = ("label_collection", "artist_collection", "song_collection")
SIMPLE_ATTRIBUTES = {
COLLECTION_STRING_ATTRIBUTES = ("label_collection", "artist_collection", "song_collection")
SIMPLE_STRING_ATTRIBUTES = {
"title": None,
"unified_title": None,
"album_status": None,
@ -225,8 +241,25 @@ class Album(MainObject):
"notes": FormattedText()
}
DOWNWARDS_COLLECTION_ATTRIBUTES = ("song_collection", )
UPWARDS_COLLECTION_ATTRIBUTES = ("artist_collection", "label_collection")
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("song_collection", )
UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("artist_collection", "label_collection")
STATIC_ATTRIBUTES = [
StaticAttribute(name="title", weight=.5),
StaticAttribute(name="unified_title", weight=.3),
StaticAttribute(name="language"),
StaticAttribute(name="barcode", weight=1),
StaticAttribute(name="albumsort"),
StaticAttribute(name="album_status"),
StaticAttribute(name="album_type", default_value=AlbumType.OTHER),
StaticAttribute(name="date", default_value=ID3Timestamp()),
StaticAttribute(name="notes", default_value=FormattedText()),
StaticAttribute(name="source_collection", is_collection=True),
StaticAttribute(name="song_collection", is_collection=True, is_downwards_collection=True),
StaticAttribute(name="artist_collection", is_collection=True, is_upwards_collection=True),
StaticAttribute(name="label_collection", is_collection=True, is_upwards_collection=True),
]
def __init__(
self,
@ -454,13 +487,13 @@ All objects dependent on Artist
class Artist(MainObject):
COLLECTION_ATTRIBUTES = (
COLLECTION_STRING_ATTRIBUTES = (
"feature_song_collection",
"main_album_collection",
"label_collection",
"source_collection"
)
SIMPLE_ATTRIBUTES = {
SIMPLE_STRING_ATTRIBUTES = {
"name": None,
"unified_name": None,
"country": None,
@ -471,8 +504,26 @@ class Artist(MainObject):
"unformated_location": None,
}
DOWNWARDS_COLLECTION_ATTRIBUTES = ("feature_song_collection", "main_album_collection")
UPWARDS_COLLECTION_ATTRIBUTES = ("label_collection", )
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("feature_song_collection", "main_album_collection")
UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("label_collection", )
STATIC_ATTRIBUTES = [
StaticAttribute(name="name", weight=.5),
StaticAttribute(name="unified_name", weight=.3),
StaticAttribute(name="country"),
StaticAttribute(name="formed_in", default_value=ID3Timestamp()),
StaticAttribute(name="lyrical_themes", default_value=[]),
StaticAttribute(name="general_genre", default_value=""),
StaticAttribute(name="notes", default_value=FormattedText()),
StaticAttribute(name="unformated_location"),
StaticAttribute(name="source_collection", is_collection=True),
StaticAttribute(name="contact_collection", is_collection=True),
StaticAttribute(name="feature_song_collection", is_collection=True, is_downwards_collection=True),
StaticAttribute(name="main_album_collection", is_collection=True, is_downwards_collection=True),
StaticAttribute(name="label_collection", is_collection=True, is_upwards_collection=True),
]
def __init__(
self,
@ -713,14 +764,23 @@ Label
class Label(MainObject):
COLLECTION_ATTRIBUTES = ("album_collection", "current_artist_collection")
SIMPLE_ATTRIBUTES = {
COLLECTION_STRING_ATTRIBUTES = ("album_collection", "current_artist_collection")
SIMPLE_STRING_ATTRIBUTES = {
"name": None,
"unified_name": None,
"notes": FormattedText()
}
DOWNWARDS_COLLECTION_ATTRIBUTES = COLLECTION_ATTRIBUTES
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = COLLECTION_STRING_ATTRIBUTES
STATIC_ATTRIBUTES = [
StaticAttribute(name="name", weight=.5),
StaticAttribute(name="unified_name", weight=.3),
StaticAttribute(name="notes", default_value=FormattedText()),
StaticAttribute(name="album_collection", is_collection=True, is_downwards_collection=True),
StaticAttribute(name="current_artist_collection", is_collection=True, is_downwards_collection=True),
]
def __init__(
self,

View File

@ -19,8 +19,8 @@ class Source(DatabaseObject):
Source(src="youtube", url="https://youtu.be/dfnsdajlhkjhsd")
```
"""
COLLECTION_ATTRIBUTES = tuple()
SIMPLE_ATTRIBUTES = {
COLLECTION_STRING_ATTRIBUTES = tuple()
SIMPLE_STRING_ATTRIBUTES = {
"page_enum": None,
"url": None,
"referer_page": None,

View File

@ -22,11 +22,11 @@ class Target(DatabaseObject):
```
"""
SIMPLE_ATTRIBUTES = {
SIMPLE_STRING_ATTRIBUTES = {
"_file": None,
"_path": None
}
COLLECTION_ATTRIBUTES = tuple()
COLLECTION_STRING_ATTRIBUTES = tuple()
def __init__(
self,

View File

@ -303,7 +303,7 @@ class Page:
if stop_at_level > 1:
collection: Collection
for collection_str in music_object.DOWNWARDS_COLLECTION_ATTRIBUTES:
for collection_str in music_object.DOWNWARDS_COLLECTION_STRING_ATTRIBUTES:
collection = music_object.__getattribute__(collection_str)
for sub_element in collection:
@ -332,7 +332,7 @@ class Page:
def fill_naming_objects(naming_music_object: DatabaseObject):
nonlocal naming_dict
for collection_name in naming_music_object.UPWARDS_COLLECTION_ATTRIBUTES:
for collection_name in naming_music_object.UPWARDS_COLLECTION_STRING_ATTRIBUTES:
collection: Collection = getattr(naming_music_object, collection_name)
if collection.empty:
@ -368,7 +368,7 @@ class Page:
download_result: DownloadResult = DownloadResult()
for collection_name in music_object.DOWNWARDS_COLLECTION_ATTRIBUTES:
for collection_name in music_object.DOWNWARDS_COLLECTION_STRING_ATTRIBUTES:
collection: Collection = getattr(music_object, collection_name)
sub_ordered_music_object: DatabaseObject