feat: new attribute system
This commit is contained in:
parent
33f97662d7
commit
ad4328dd11
@ -19,7 +19,7 @@ Additionally it provides an **Interface** to:
|
|||||||
|
|
||||||
### DatabaseObject.merge()
|
### 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.
|
The simple attributes just get carried from the other instance, to the self instance.
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ from .parents import DatabaseObject
|
|||||||
|
|
||||||
|
|
||||||
class Contact(DatabaseObject):
|
class Contact(DatabaseObject):
|
||||||
COLLECTION_ATTRIBUTES = tuple()
|
COLLECTION_STRING_ATTRIBUTES = tuple()
|
||||||
SIMPLE_ATTRIBUTES = {
|
SIMPLE_STRING_ATTRIBUTES = {
|
||||||
"contact_method": None,
|
"contact_method": None,
|
||||||
"value": None,
|
"value": None,
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@ from .formatted_text import FormattedText
|
|||||||
|
|
||||||
|
|
||||||
class Lyrics(DatabaseObject):
|
class Lyrics(DatabaseObject):
|
||||||
COLLECTION_ATTRIBUTES = ("source_collection",)
|
COLLECTION_STRING_ATTRIBUTES = ("source_collection",)
|
||||||
SIMPLE_ATTRIBUTES = {
|
SIMPLE_STRING_ATTRIBUTES = {
|
||||||
"text": FormattedText(),
|
"text": FormattedText(),
|
||||||
"language": None
|
"language": None
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import random
|
import random
|
||||||
from collections import defaultdict
|
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 .metadata import Metadata
|
||||||
from .option import Options
|
from .option import Options
|
||||||
@ -10,15 +11,46 @@ from ..utils.config import main_settings, logging_settings
|
|||||||
|
|
||||||
LOGGER = logging_settings["object_logger"]
|
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:
|
class DatabaseObject:
|
||||||
COLLECTION_ATTRIBUTES: tuple = tuple()
|
COLLECTION_STRING_ATTRIBUTES: tuple = tuple()
|
||||||
SIMPLE_ATTRIBUTES: dict = dict()
|
SIMPLE_STRING_ATTRIBUTES: dict = dict()
|
||||||
|
|
||||||
# contains all collection attributes, which describe something "smaller"
|
# contains all collection attributes, which describe something "smaller"
|
||||||
# e.g. album has songs, but not artist.
|
# e.g. album has songs, but not artist.
|
||||||
DOWNWARDS_COLLECTION_ATTRIBUTES: tuple = tuple()
|
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES: tuple = tuple()
|
||||||
UPWARDS_COLLECTION_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:
|
def __init__(self, _id: int = None, dynamic: bool = False, **kwargs) -> None:
|
||||||
self.automatic_id: bool = False
|
self.automatic_id: bool = False
|
||||||
@ -33,13 +65,43 @@ class DatabaseObject:
|
|||||||
self.automatic_id = True
|
self.automatic_id = True
|
||||||
# LOGGER.debug(f"Id for {type(self).__name__} isn't set. Setting to {_id}")
|
# 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)
|
# The id can only be None, if the object is dynamic (self.dynamic = True)
|
||||||
self.id: Optional[int] = _id
|
self.id: Optional[int] = _id
|
||||||
|
|
||||||
self.dynamic = dynamic
|
self.dynamic = dynamic
|
||||||
|
|
||||||
self.build_version = -1
|
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):
|
def __hash__(self):
|
||||||
if self.dynamic:
|
if self.dynamic:
|
||||||
raise TypeError("Dynamic DatabaseObjects are unhashable.")
|
raise TypeError("Dynamic DatabaseObjects are unhashable.")
|
||||||
@ -89,10 +151,10 @@ class DatabaseObject:
|
|||||||
LOGGER.warning(f"can't merge \"{type(other)}\" into \"{type(self)}\"")
|
LOGGER.warning(f"can't merge \"{type(other)}\" into \"{type(self)}\"")
|
||||||
return
|
return
|
||||||
|
|
||||||
for collection in type(self).COLLECTION_ATTRIBUTES:
|
for collection in type(self).COLLECTION_STRING_ATTRIBUTES:
|
||||||
getattr(self, collection).extend(getattr(other, collection))
|
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:
|
if getattr(other, simple_attribute) == default_value:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -100,7 +162,7 @@ class DatabaseObject:
|
|||||||
setattr(self, simple_attribute, getattr(other, simple_attribute))
|
setattr(self, simple_attribute, getattr(other, simple_attribute))
|
||||||
|
|
||||||
def strip_details(self):
|
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()
|
getattr(self, collection).clear()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -15,7 +15,7 @@ from .metadata import (
|
|||||||
Metadata
|
Metadata
|
||||||
)
|
)
|
||||||
from .option import Options
|
from .option import Options
|
||||||
from .parents import MainObject, DatabaseObject
|
from .parents import MainObject, DatabaseObject, StaticAttribute
|
||||||
from .source import Source, SourceCollection
|
from .source import Source, SourceCollection
|
||||||
from .target import Target
|
from .target import Target
|
||||||
from ..utils.string_processing import unify
|
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.
|
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",
|
"lyrics_collection", "album_collection", "main_artist_collection", "feature_artist_collection",
|
||||||
"source_collection")
|
"source_collection")
|
||||||
SIMPLE_ATTRIBUTES = {
|
SIMPLE_STRING_ATTRIBUTES = {
|
||||||
"title": None,
|
"title": None,
|
||||||
"unified_title": None,
|
"unified_title": None,
|
||||||
"isrc": None,
|
"isrc": None,
|
||||||
@ -49,7 +49,23 @@ class Song(MainObject):
|
|||||||
"notes": FormattedText()
|
"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__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -212,8 +228,8 @@ All objects dependent on Album
|
|||||||
|
|
||||||
|
|
||||||
class Album(MainObject):
|
class Album(MainObject):
|
||||||
COLLECTION_ATTRIBUTES = ("label_collection", "artist_collection", "song_collection")
|
COLLECTION_STRING_ATTRIBUTES = ("label_collection", "artist_collection", "song_collection")
|
||||||
SIMPLE_ATTRIBUTES = {
|
SIMPLE_STRING_ATTRIBUTES = {
|
||||||
"title": None,
|
"title": None,
|
||||||
"unified_title": None,
|
"unified_title": None,
|
||||||
"album_status": None,
|
"album_status": None,
|
||||||
@ -225,8 +241,25 @@ class Album(MainObject):
|
|||||||
"notes": FormattedText()
|
"notes": FormattedText()
|
||||||
}
|
}
|
||||||
|
|
||||||
DOWNWARDS_COLLECTION_ATTRIBUTES = ("song_collection", )
|
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("song_collection", )
|
||||||
UPWARDS_COLLECTION_ATTRIBUTES = ("artist_collection", "label_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__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -454,13 +487,13 @@ All objects dependent on Artist
|
|||||||
|
|
||||||
|
|
||||||
class Artist(MainObject):
|
class Artist(MainObject):
|
||||||
COLLECTION_ATTRIBUTES = (
|
COLLECTION_STRING_ATTRIBUTES = (
|
||||||
"feature_song_collection",
|
"feature_song_collection",
|
||||||
"main_album_collection",
|
"main_album_collection",
|
||||||
"label_collection",
|
"label_collection",
|
||||||
"source_collection"
|
"source_collection"
|
||||||
)
|
)
|
||||||
SIMPLE_ATTRIBUTES = {
|
SIMPLE_STRING_ATTRIBUTES = {
|
||||||
"name": None,
|
"name": None,
|
||||||
"unified_name": None,
|
"unified_name": None,
|
||||||
"country": None,
|
"country": None,
|
||||||
@ -471,8 +504,26 @@ class Artist(MainObject):
|
|||||||
"unformated_location": None,
|
"unformated_location": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
DOWNWARDS_COLLECTION_ATTRIBUTES = ("feature_song_collection", "main_album_collection")
|
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("feature_song_collection", "main_album_collection")
|
||||||
UPWARDS_COLLECTION_ATTRIBUTES = ("label_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__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -713,14 +764,23 @@ Label
|
|||||||
|
|
||||||
|
|
||||||
class Label(MainObject):
|
class Label(MainObject):
|
||||||
COLLECTION_ATTRIBUTES = ("album_collection", "current_artist_collection")
|
COLLECTION_STRING_ATTRIBUTES = ("album_collection", "current_artist_collection")
|
||||||
SIMPLE_ATTRIBUTES = {
|
SIMPLE_STRING_ATTRIBUTES = {
|
||||||
"name": None,
|
"name": None,
|
||||||
"unified_name": None,
|
"unified_name": None,
|
||||||
"notes": FormattedText()
|
"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__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -19,8 +19,8 @@ class Source(DatabaseObject):
|
|||||||
Source(src="youtube", url="https://youtu.be/dfnsdajlhkjhsd")
|
Source(src="youtube", url="https://youtu.be/dfnsdajlhkjhsd")
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
COLLECTION_ATTRIBUTES = tuple()
|
COLLECTION_STRING_ATTRIBUTES = tuple()
|
||||||
SIMPLE_ATTRIBUTES = {
|
SIMPLE_STRING_ATTRIBUTES = {
|
||||||
"page_enum": None,
|
"page_enum": None,
|
||||||
"url": None,
|
"url": None,
|
||||||
"referer_page": None,
|
"referer_page": None,
|
||||||
|
@ -22,11 +22,11 @@ class Target(DatabaseObject):
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SIMPLE_ATTRIBUTES = {
|
SIMPLE_STRING_ATTRIBUTES = {
|
||||||
"_file": None,
|
"_file": None,
|
||||||
"_path": None
|
"_path": None
|
||||||
}
|
}
|
||||||
COLLECTION_ATTRIBUTES = tuple()
|
COLLECTION_STRING_ATTRIBUTES = tuple()
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -303,7 +303,7 @@ class Page:
|
|||||||
|
|
||||||
if stop_at_level > 1:
|
if stop_at_level > 1:
|
||||||
collection: Collection
|
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)
|
collection = music_object.__getattribute__(collection_str)
|
||||||
|
|
||||||
for sub_element in collection:
|
for sub_element in collection:
|
||||||
@ -332,7 +332,7 @@ class Page:
|
|||||||
def fill_naming_objects(naming_music_object: DatabaseObject):
|
def fill_naming_objects(naming_music_object: DatabaseObject):
|
||||||
nonlocal naming_dict
|
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)
|
collection: Collection = getattr(naming_music_object, collection_name)
|
||||||
|
|
||||||
if collection.empty:
|
if collection.empty:
|
||||||
@ -368,7 +368,7 @@ class Page:
|
|||||||
|
|
||||||
download_result: DownloadResult = DownloadResult()
|
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)
|
collection: Collection = getattr(music_object, collection_name)
|
||||||
|
|
||||||
sub_ordered_music_object: DatabaseObject
|
sub_ordered_music_object: DatabaseObject
|
||||||
|
Loading…
Reference in New Issue
Block a user