diff options
author | Mike Crute <mike@crute.us> | 2017-10-30 02:32:04 +0000 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2017-10-30 02:32:04 +0000 |
commit | 71677cc962218a0001ef9d9b4404179995cc21ef (patch) | |
tree | 743853f3671a1149343ca7f8e7b2a9323dc6c662 /pandora | |
parent | 2740e2c88f952b7b6ca29ef0dc6216c5ac19c7b1 (diff) | |
download | pydora-71677cc962218a0001ef9d9b4404179995cc21ef.tar.bz2 pydora-71677cc962218a0001ef9d9b4404179995cc21ef.tar.xz pydora-71677cc962218a0001ef9d9b4404179995cc21ef.zip |
Refactor sub-model building
These used to be done with formatters but that was somewhat an abuse of
the formatter model in the first place. This changeset adds a model
attribute that will cause the underlying model builder to dynamically
construct a model or list of models depending on the incoming data type.
Diffstat (limited to 'pandora')
-rw-r--r-- | pandora/models/__init__.py | 20 | ||||
-rw-r--r-- | pandora/models/pandora.py | 12 |
2 files changed, 18 insertions, 14 deletions
diff --git a/pandora/models/__init__.py b/pandora/models/__init__.py index 5b25de2..141a64b 100644 --- a/pandora/models/__init__.py +++ b/pandora/models/__init__.py | |||
@@ -3,7 +3,7 @@ from collections import namedtuple | |||
3 | from ..py2compat import with_metaclass | 3 | from ..py2compat import with_metaclass |
4 | 4 | ||
5 | 5 | ||
6 | class Field(namedtuple("Field", ["field", "default", "formatter"])): | 6 | class Field(namedtuple("Field", ["field", "default", "formatter", "model"])): |
7 | """Model Field | 7 | """Model Field |
8 | 8 | ||
9 | Model fields represent JSON key/value pairs. When added to a PandoraModel | 9 | Model fields represent JSON key/value pairs. When added to a PandoraModel |
@@ -26,8 +26,8 @@ class Field(namedtuple("Field", ["field", "default", "formatter"])): | |||
26 | model based on the type of data in the JSON | 26 | model based on the type of data in the JSON |
27 | """ | 27 | """ |
28 | 28 | ||
29 | def __new__(cls, field, default=None, formatter=None): | 29 | def __new__(cls, field, default=None, formatter=None, model=None): |
30 | return super(Field, cls).__new__(cls, field, default, formatter) | 30 | return super(Field, cls).__new__(cls, field, default, formatter, model) |
31 | 31 | ||
32 | 32 | ||
33 | class SyntheticField(namedtuple("SyntheticField", ["field"])): | 33 | class SyntheticField(namedtuple("SyntheticField", ["field"])): |
@@ -39,8 +39,6 @@ class SyntheticField(namedtuple("SyntheticField", ["field"])): | |||
39 | payload. | 39 | payload. |
40 | """ | 40 | """ |
41 | 41 | ||
42 | default = None | ||
43 | |||
44 | @staticmethod | 42 | @staticmethod |
45 | def formatter(api_client, field, data): # pragma: no cover | 43 | def formatter(api_client, field, data): # pragma: no cover |
46 | """Format Value for Model | 44 | """Format Value for Model |
@@ -100,7 +98,7 @@ class PandoraModel(with_metaclass(ModelMetaClass, object)): | |||
100 | safe_types = (type(None), str, bytes, int, bool) | 98 | safe_types = (type(None), str, bytes, int, bool) |
101 | 99 | ||
102 | for key, value in self._fields.items(): | 100 | for key, value in self._fields.items(): |
103 | default = value.default | 101 | default = getattr(value, "default", None) |
104 | 102 | ||
105 | if not isinstance(default, safe_types): | 103 | if not isinstance(default, safe_types): |
106 | default = type(default)() | 104 | default = type(default)() |
@@ -117,13 +115,21 @@ class PandoraModel(with_metaclass(ModelMetaClass, object)): | |||
117 | this function runs even if they are missing from the incoming JSON. | 115 | this function runs even if they are missing from the incoming JSON. |
118 | """ | 116 | """ |
119 | for key, value in instance.__class__._fields.items(): | 117 | for key, value in instance.__class__._fields.items(): |
120 | newval = data.get(value.field, value.default) | 118 | default = getattr(value, "default", None) |
119 | newval = data.get(value.field, default) | ||
121 | 120 | ||
122 | if isinstance(value, SyntheticField): | 121 | if isinstance(value, SyntheticField): |
123 | newval = value.formatter(api_client, value.field, data, newval) | 122 | newval = value.formatter(api_client, value.field, data, newval) |
124 | setattr(instance, key, newval) | 123 | setattr(instance, key, newval) |
125 | continue | 124 | continue |
126 | 125 | ||
126 | model_class = getattr(value, "model", None) | ||
127 | if newval and model_class: | ||
128 | if isinstance(newval, list): | ||
129 | newval = model_class.from_json_list(api_client, newval) | ||
130 | else: | ||
131 | newval = model_class.from_json(api_client, newval) | ||
132 | |||
127 | if newval and value.formatter: | 133 | if newval and value.formatter: |
128 | newval = value.formatter(api_client, newval) | 134 | newval = value.formatter(api_client, newval) |
129 | 135 | ||
diff --git a/pandora/models/pandora.py b/pandora/models/pandora.py index d7d2bf1..71a1d51 100644 --- a/pandora/models/pandora.py +++ b/pandora/models/pandora.py | |||
@@ -253,8 +253,8 @@ class Bookmark(PandoraModel): | |||
253 | 253 | ||
254 | class BookmarkList(PandoraModel): | 254 | class BookmarkList(PandoraModel): |
255 | 255 | ||
256 | songs = Field("songs", formatter=Bookmark.from_json_list) | 256 | songs = Field("songs", model=Bookmark) |
257 | artists = Field("artists", formatter=Bookmark.from_json_list) | 257 | artists = Field("artists", model=Bookmark) |
258 | 258 | ||
259 | 259 | ||
260 | class SearchResultItem(PandoraModel): | 260 | class SearchResultItem(PandoraModel): |
@@ -344,11 +344,9 @@ class SearchResult(PandoraModel): | |||
344 | 344 | ||
345 | nearest_matches_available = Field("nearMatchesAvailable") | 345 | nearest_matches_available = Field("nearMatchesAvailable") |
346 | explanation = Field("explanation") | 346 | explanation = Field("explanation") |
347 | songs = Field("songs", formatter=SongSearchResultItem.from_json_list) | 347 | songs = Field("songs", model=SongSearchResultItem) |
348 | artists = Field("artists", formatter=ArtistSearchResultItem.from_json_list) | 348 | artists = Field("artists", model=ArtistSearchResultItem) |
349 | genre_stations = Field( | 349 | genre_stations = Field("genreStations", model=GenreStationSearchResultItem) |
350 | "genreStations", | ||
351 | formatter=GenreStationSearchResultItem.from_json_list) | ||
352 | 350 | ||
353 | 351 | ||
354 | class GenreStationList(PandoraDictListModel): | 352 | class GenreStationList(PandoraDictListModel): |