models: Convert all models to using fields.
This commit is contained in:
parent
07912e1091
commit
4faf4de7aa
125
mopidy/models.py
125
mopidy/models.py
@ -128,12 +128,15 @@ class ImmutableObject(object):
|
||||
|
||||
"""
|
||||
Superclass for immutable objects whose fields can only be modified via the
|
||||
constructor.
|
||||
constructor. Fields should be :class:`Field` instances to ensure type
|
||||
safety in our models.
|
||||
|
||||
:param kwargs: kwargs to set as fields on the object
|
||||
:type kwargs: any
|
||||
"""
|
||||
|
||||
__metaclass__ = FieldOwner
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
if not hasattr(self, key) or callable(getattr(self, key)):
|
||||
@ -142,7 +145,7 @@ class ImmutableObject(object):
|
||||
key)
|
||||
if value == getattr(self, key):
|
||||
continue # Don't explicitly set default values
|
||||
self.__dict__[key] = value
|
||||
super(ImmutableObject, self).__setattr__(key, value)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name.startswith('_'):
|
||||
@ -192,7 +195,7 @@ class ImmutableObject(object):
|
||||
:type values: dict
|
||||
:rtype: new instance of the model being copied
|
||||
"""
|
||||
data = {}
|
||||
data = {} # TODO: do we need public key handling now?
|
||||
for key in self.__dict__.keys():
|
||||
public_key = key.lstrip('_')
|
||||
value = values.pop(public_key, self.__dict__[key])
|
||||
@ -207,7 +210,7 @@ class ImmutableObject(object):
|
||||
return self.__class__(**data)
|
||||
|
||||
def serialize(self):
|
||||
data = {}
|
||||
data = {} # TODO: do we need public key handling now?
|
||||
data['__model__'] = self.__class__.__name__
|
||||
for key in self.__dict__.keys():
|
||||
public_key = key.lstrip('_')
|
||||
@ -282,14 +285,10 @@ class Ref(ImmutableObject):
|
||||
"""
|
||||
|
||||
#: The object URI. Read-only.
|
||||
uri = None
|
||||
uri = String()
|
||||
|
||||
#: The object name. Read-only.
|
||||
name = None
|
||||
|
||||
#: The object type, e.g. "artist", "album", "track", "playlist",
|
||||
#: "directory". Read-only.
|
||||
type = None
|
||||
name = String()
|
||||
|
||||
#: Constant used for comparison with the :attr:`type` field.
|
||||
ALBUM = 'album'
|
||||
@ -306,6 +305,10 @@ class Ref(ImmutableObject):
|
||||
#: Constant used for comparison with the :attr:`type` field.
|
||||
TRACK = 'track'
|
||||
|
||||
#: The object type, e.g. "artist", "album", "track", "playlist",
|
||||
#: "directory". Read-only.
|
||||
type = Field(choices=(ALBUM, ARTIST, DIRECTORY, PLAYLIST, TRACK))
|
||||
|
||||
@classmethod
|
||||
def album(cls, **kwargs):
|
||||
"""Create a :class:`Ref` with ``type`` :attr:`ALBUM`."""
|
||||
@ -346,13 +349,13 @@ class Image(ImmutableObject):
|
||||
"""
|
||||
|
||||
#: The image URI. Read-only.
|
||||
uri = None
|
||||
uri = String()
|
||||
|
||||
#: Optional width of the image or :class:`None`. Read-only.
|
||||
width = None
|
||||
width = Integer(min=0)
|
||||
|
||||
#: Optional height of the image or :class:`None`. Read-only.
|
||||
height = None
|
||||
height = Integer(min=0)
|
||||
|
||||
|
||||
class Artist(ImmutableObject):
|
||||
@ -367,13 +370,13 @@ class Artist(ImmutableObject):
|
||||
"""
|
||||
|
||||
#: The artist URI. Read-only.
|
||||
uri = None
|
||||
uri = String()
|
||||
|
||||
#: The artist name. Read-only.
|
||||
name = None
|
||||
name = String()
|
||||
|
||||
#: The MusicBrainz ID of the artist. Read-only.
|
||||
musicbrainz_id = None
|
||||
musicbrainz_id = String()
|
||||
|
||||
|
||||
class Album(ImmutableObject):
|
||||
@ -398,37 +401,32 @@ class Album(ImmutableObject):
|
||||
"""
|
||||
|
||||
#: The album URI. Read-only.
|
||||
uri = None
|
||||
uri = String()
|
||||
|
||||
#: The album name. Read-only.
|
||||
name = None
|
||||
name = String()
|
||||
|
||||
#: A set of album artists. Read-only.
|
||||
artists = frozenset()
|
||||
artists = Collection(type=Artist, container=frozenset)
|
||||
|
||||
#: The number of tracks in the album. Read-only.
|
||||
num_tracks = None
|
||||
num_tracks = Integer(min=0)
|
||||
|
||||
#: The number of discs in the album. Read-only.
|
||||
num_discs = None
|
||||
num_discs = Integer(min=0)
|
||||
|
||||
#: The album release date. Read-only.
|
||||
date = None
|
||||
date = String() # TODO: add date type
|
||||
|
||||
#: The MusicBrainz ID of the album. Read-only.
|
||||
musicbrainz_id = None
|
||||
musicbrainz_id = String()
|
||||
|
||||
#: The album image URIs. Read-only.
|
||||
images = frozenset()
|
||||
images = Collection(type=basestring, container=frozenset)
|
||||
# XXX If we want to keep the order of images we shouldn't use frozenset()
|
||||
# as it doesn't preserve order. I'm deferring this issue until we got
|
||||
# actual usage of this field with more than one image.
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.__dict__['artists'] = frozenset(kwargs.pop('artists', None) or [])
|
||||
self.__dict__['images'] = frozenset(kwargs.pop('images', None) or [])
|
||||
super(Album, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class Track(ImmutableObject):
|
||||
|
||||
@ -466,61 +464,52 @@ class Track(ImmutableObject):
|
||||
"""
|
||||
|
||||
#: The track URI. Read-only.
|
||||
uri = None
|
||||
uri = String()
|
||||
|
||||
#: The track name. Read-only.
|
||||
name = None
|
||||
name = String()
|
||||
|
||||
#: A set of track artists. Read-only.
|
||||
artists = frozenset()
|
||||
artists = Collection(type=Artist, container=frozenset)
|
||||
|
||||
#: The track :class:`Album`. Read-only.
|
||||
album = None
|
||||
album = Field(type=Album)
|
||||
|
||||
#: A set of track composers. Read-only.
|
||||
composers = frozenset()
|
||||
composers = Collection(type=Artist, container=frozenset)
|
||||
|
||||
#: A set of track performers`. Read-only.
|
||||
performers = frozenset()
|
||||
performers = Collection(type=Artist, container=frozenset)
|
||||
|
||||
#: The track genre. Read-only.
|
||||
genre = None
|
||||
genre = String()
|
||||
|
||||
#: The track number in the album. Read-only.
|
||||
track_no = None
|
||||
track_no = Integer(min=0)
|
||||
|
||||
#: The disc number in the album. Read-only.
|
||||
disc_no = None
|
||||
disc_no = Integer(min=0)
|
||||
|
||||
#: The track release date. Read-only.
|
||||
date = None
|
||||
date = String() # TODO: add date type
|
||||
|
||||
#: The track length in milliseconds. Read-only.
|
||||
length = None
|
||||
length = Integer(min=0)
|
||||
|
||||
#: The track's bitrate in kbit/s. Read-only.
|
||||
bitrate = None
|
||||
bitrate = Integer(min=0)
|
||||
|
||||
#: The track comment. Read-only.
|
||||
comment = None
|
||||
comment = String()
|
||||
|
||||
#: The MusicBrainz ID of the track. Read-only.
|
||||
musicbrainz_id = None
|
||||
musicbrainz_id = String()
|
||||
|
||||
#: Integer representing when the track was last modified. Exact meaning
|
||||
#: depends on source of track. For local files this is the modification
|
||||
#: time in milliseconds since Unix epoch. For other backends it could be an
|
||||
#: equivalent timestamp or simply a version counter.
|
||||
last_modified = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def get(key):
|
||||
return frozenset(kwargs.pop(key, None) or [])
|
||||
|
||||
self.__dict__['artists'] = get('artists')
|
||||
self.__dict__['composers'] = get('composers')
|
||||
self.__dict__['performers'] = get('performers')
|
||||
super(Track, self).__init__(*args, **kwargs)
|
||||
last_modified = Integer(min=0)
|
||||
|
||||
|
||||
class TlTrack(ImmutableObject):
|
||||
@ -546,10 +535,10 @@ class TlTrack(ImmutableObject):
|
||||
"""
|
||||
|
||||
#: The tracklist ID. Read-only.
|
||||
tlid = None
|
||||
tlid = Integer(min=0)
|
||||
|
||||
#: The track. Read-only.
|
||||
track = None
|
||||
track = Field(type=Track)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if len(args) == 2 and len(kwargs) == 0:
|
||||
@ -577,23 +566,19 @@ class Playlist(ImmutableObject):
|
||||
"""
|
||||
|
||||
#: The playlist URI. Read-only.
|
||||
uri = None
|
||||
uri = String()
|
||||
|
||||
#: The playlist name. Read-only.
|
||||
name = None
|
||||
name = String()
|
||||
|
||||
#: The playlist's tracks. Read-only.
|
||||
tracks = tuple()
|
||||
tracks = Collection(type=Track, container=tuple)
|
||||
|
||||
#: The playlist modification time in milliseconds since Unix epoch.
|
||||
#: Read-only.
|
||||
#:
|
||||
#: Integer, or :class:`None` if unknown.
|
||||
last_modified = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.__dict__['tracks'] = tuple(kwargs.pop('tracks', None) or [])
|
||||
super(Playlist, self).__init__(*args, **kwargs)
|
||||
last_modified = Integer(min=0)
|
||||
|
||||
# TODO: def insert(self, pos, track): ... ?
|
||||
|
||||
@ -617,19 +602,13 @@ class SearchResult(ImmutableObject):
|
||||
"""
|
||||
|
||||
# The search result URI. Read-only.
|
||||
uri = None
|
||||
uri = String()
|
||||
|
||||
# The tracks matching the search query. Read-only.
|
||||
tracks = tuple()
|
||||
tracks = Collection(type=Track, container=tuple)
|
||||
|
||||
# The artists matching the search query. Read-only.
|
||||
artists = tuple()
|
||||
artists = Collection(type=Artist, container=tuple)
|
||||
|
||||
# The albums matching the search query. Read-only.
|
||||
albums = tuple()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.__dict__['tracks'] = tuple(kwargs.pop('tracks', None) or [])
|
||||
self.__dict__['artists'] = tuple(kwargs.pop('artists', None) or [])
|
||||
self.__dict__['albums'] = tuple(kwargs.pop('albums', None) or [])
|
||||
super(SearchResult, self).__init__(*args, **kwargs)
|
||||
albums = Collection(type=Album, container=tuple)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user