diff --git a/tests/test_utils.py b/tests/test_utils.py index a90e5b8..3c94218 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -70,8 +70,12 @@ def test_build_uri(): 'users/sean/watched/movies' assert build_uri('shows/popular', page=2, limit=10) == \ 'shows/popular?page=2&limit=10' - assert build_uri('shows/popular?extended={extended}', extended='full', - page=2) == 'shows/popular?extended=full&page=2' + assert build_uri('shows/popular', extended='full') == \ + 'shows/popular?extended=full' + assert build_uri('shows/popular', page=2, extended='full') == \ + 'shows/popular?page=2&extended=full' + assert build_uri('shows/popular?sort=rank', page=2) == \ + 'shows/popular?sort=rank&page=2' def test_build_uri_pagination_validation(): diff --git a/trakt/calendar.py b/trakt/calendar.py index f1a517c..ecf3a8e 100644 --- a/trakt/calendar.py +++ b/trakt/calendar.py @@ -6,7 +6,7 @@ from trakt.core import get from trakt.movies import Movie from trakt.tv import TVEpisode, TVShow -from trakt.utils import airs_date, now +from trakt.utils import airs_date, build_uri, now __author__ = 'Jon Nappi' __all__ = ['Calendar', 'PremiereCalendar', 'MyPremiereCalendar', @@ -57,10 +57,8 @@ def __str__(self): @property def ext(self): """construct the fully formatted url for this Calendar""" - uri = '/'.join([self.url, str(self.date), str(self.days)]) - if self.extended: - uri += '?extended={extended}'.format(extended=self.extended) - return uri + return build_uri('{url}/{date}/{days}', url=self.url, date=self.date, + days=self.days, extended=self.extended) @get def _get(self): diff --git a/trakt/movies.py b/trakt/movies.py index b84b61a..983b3e3 100644 --- a/trakt/movies.py +++ b/trakt/movies.py @@ -10,7 +10,7 @@ add_to_watchlist, checkin_media, comment, delete_checkin, rate, remove_from_collection, remove_from_history, remove_from_watchlist, search) -from trakt.utils import now, slugify +from trakt.utils import build_uri, now, slugify __author__ = 'Jon Nappi' __all__ = ['dismiss_recommendation', 'get_recommended_movies', 'genres', @@ -144,17 +144,17 @@ def _build(self, data): @property def ext(self): """Base uri to retrieve basic information about this :class:`Movie`""" - return 'movies/{slug}'.format(slug=self.slug) + return build_uri('movies/{slug}', slug=self.slug) @property def ext_full(self): """Uri to retrieve all information about this :class:`Movie`""" - return self.ext + '?extended=full' + return build_uri(self.ext, extended='full') @property def images_ext(self): """Uri to retrieve additional image information""" - return self.ext + '?extended=images' + return build_uri(self.ext, extended='images') @property @get diff --git a/trakt/people.py b/trakt/people.py index 61a3cb2..2bbf8e8 100644 --- a/trakt/people.py +++ b/trakt/people.py @@ -4,7 +4,7 @@ from trakt.core import get from trakt.mixins import IdsMixin from trakt.sync import search -from trakt.utils import slugify +from trakt.utils import build_uri, slugify __author__ = 'Jon Nappi' __all__ = ['Person', 'ActingCredit', 'CrewCredit', 'Credits', 'MovieCredits', @@ -40,15 +40,15 @@ def search(name, year=None): @property def ext(self): - return 'people/{id}'.format(id=self.slug) + return build_uri('people/{id}', id=self.slug) @property def ext_full(self): - return self.ext + '?extended=full' + return build_uri(self.ext, extended='full') @property def images_ext(self): - return self.ext + '?extended=images' + return build_uri(self.ext, extended='images') @property def ext_movie_credits(self): diff --git a/trakt/sync.py b/trakt/sync.py index 27382bd..82c2865 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -10,7 +10,7 @@ from trakt.core import delete, get, post from trakt.mixins import IdsMixin -from trakt.utils import slugify, timestamp +from trakt.utils import build_uri, slugify, timestamp __author__ = 'Jon Nappi' __all__ = ['Scrobbler', 'comment', 'rate', 'add_to_history', 'get_collection', @@ -469,12 +469,10 @@ def get_watched(list_type=None, extended=None): if list_type and list_type not in valid_type: raise ValueError('list_type must be one of {}'.format(valid_type)) - uri = 'sync/watched' - if list_type: - uri += '/{}'.format(list_type) - - if list_type == 'shows' and extended: - uri += '?extended={extended}'.format(extended=extended) + uri = (build_uri('sync/watched/{list_type}', list_type=list_type) + if list_type else 'sync/watched') + if list_type == 'shows': + uri = build_uri(uri, extended=extended) data = yield uri results = [] @@ -508,12 +506,9 @@ def get_collection(list_type=None, extended=None): if list_type and list_type not in valid_type: raise ValueError('list_type must be one of {}'.format(valid_type)) - uri = 'sync/collection' - if list_type: - uri += '/{}'.format(list_type) - - if extended: - uri += '?extended={extended}'.format(extended=extended) + uri = (build_uri('sync/collection/{list_type}', list_type=list_type) + if list_type else 'sync/collection') + uri = build_uri(uri, extended=extended) data = yield uri results = [] diff --git a/trakt/tv.py b/trakt/tv.py index e86ee88..262f834 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -13,7 +13,7 @@ add_to_watchlist, checkin_media, comment, delete_checkin, rate, remove_from_collection, remove_from_history, remove_from_watchlist, search) -from trakt.utils import airs_date, slugify +from trakt.utils import airs_date, build_uri, slugify __author__ = 'Jon Nappi' __all__ = ['dismiss_recommendation', 'get_recommended_shows', 'genres', @@ -44,9 +44,7 @@ def get_recommended_shows(page=1, limit=10): history and your friends. Results are returned with the top recommendation first. """ - data = yield 'recommendations/shows?page={page}&limit={limit}'.format( - page=page, limit=limit - ) + data = yield build_uri('recommendations/shows', page=page, limit=limit) yield [TVShow(**show) for show in data] @@ -59,11 +57,7 @@ def genres(): @get def popular_shows(page=1, limit=10, extended=None): - uri = 'shows/popular?page={page}&limit={limit}'.format( - page=page, limit=limit - ) - if extended: - uri += '&extended={extended}'.format(extended=extended) + uri = build_uri('shows/popular', page=page, limit=limit, extended=extended) data = yield uri yield [TVShow(**show) for show in data] @@ -72,11 +66,7 @@ def popular_shows(page=1, limit=10, extended=None): @get def trending_shows(page=1, limit=10, extended=None): """All :class:`TVShow`'s being watched right now""" - uri = 'shows/trending?page={page}&limit={limit}'.format( - page=page, limit=limit - ) - if extended: - uri += '&extended={extended}'.format(extended=extended) + uri = build_uri('shows/trending', page=page, limit=limit, extended=extended) data = yield uri yield [TVShow(**show['show']) for show in data] @@ -90,11 +80,8 @@ def updated_shows(timestamp=None, page=1, limit=10, extended=None): """ y_day = datetime.now() - timedelta(1) ts = timestamp or int(y_day.strftime('%s')) * 1000 - uri = 'shows/updates/{start_date}?page={page}&limit={limit}'.format( - start_date=ts, page=page, limit=limit - ) - if extended: - uri += '&extended={extended}'.format(extended=extended) + uri = build_uri('shows/updates/{start_date}', start_date=ts, page=page, + limit=limit, extended=extended) data = yield uri yield [TVShow(**show) for show in data] @@ -111,11 +98,9 @@ def recommended_shows(time_period='weekly', page=1, limit=10, extended=None): valid_time_period )) - uri = 'shows/recommended/{time_period}?page={page}&limit={limit}'.format( - time_period=time_period, page=page, limit=limit - ) - if extended: - uri += '&extended={extended}'.format(extended=extended) + uri = build_uri('shows/recommended/{time_period}', + time_period=time_period, page=page, limit=limit, + extended=extended) data = yield uri yield [TVShow(**show['show']) for show in data] @@ -134,11 +119,8 @@ def played_shows(time_period='weekly', page=1, limit=10, extended=None): valid_time_period )) - uri = 'shows/played/{time_period}?page={page}&limit={limit}'.format( - time_period=time_period, page=page, limit=limit - ) - if extended: - uri += '&extended={extended}'.format(extended=extended) + uri = build_uri('shows/played/{time_period}', time_period=time_period, + page=page, limit=limit, extended=extended) data = yield uri yield [TVShow(**show['show']) for show in data] @@ -156,11 +138,8 @@ def watched_shows(time_period='weekly', page=1, limit=10, extended=None): valid_time_period )) - uri = 'shows/watched/{time_period}?page={page}&limit={limit}'.format( - time_period=time_period, page=page, limit=limit - ) - if extended: - uri += '&extended={extended}'.format(extended=extended) + uri = build_uri('shows/watched/{time_period}', time_period=time_period, + page=page, limit=limit, extended=extended) data = yield uri yield [TVShow(**show['show']) for show in data] @@ -178,11 +157,9 @@ def collected_shows(time_period='weekly', page=1, limit=10, extended=None): valid_time_period )) - uri = 'shows/collected/{time_period}?page={page}&limit={limit}'.format( - time_period=time_period, page=page, limit=limit - ) - if extended: - uri += '&extended={extended}'.format(extended=extended) + uri = build_uri('shows/collected/{time_period}', + time_period=time_period, page=page, limit=limit, + extended=extended) data = yield uri yield [TVShow(**show['show']) for show in data] @@ -194,11 +171,8 @@ def anticipated_shows(page=1, limit=10, extended=None): Return most anticipated shows based on the number of lists a show appears on. """ - uri = 'shows/anticipated?page={page}&limit={limit}'.format( - page=page, limit=limit - ) - if extended: - uri += '&extended={extended}'.format(extended=extended) + uri = build_uri('shows/anticipated', page=page, limit=limit, + extended=extended) data = yield uri yield [TVShow(**show['show']) for show in data] @@ -270,16 +244,16 @@ def _build(self, data): @property def ext(self): - return 'shows/{slug}'.format(slug=self.trakt or self.slug) + return build_uri('shows/{slug}', slug=self.trakt or self.slug) @property def ext_full(self): - return self.ext + '?extended=full' + return build_uri(self.ext, extended='full') @property def images_ext(self): """Uri to retrieve additional image information.""" - return self.ext + '?extended=images' + return build_uri(self.ext, extended='images') @property @get @@ -438,7 +412,7 @@ def seasons(self): seasons which each contain :class:`TVEpisode` elements """ if self._seasons is None: - data = yield self.ext + '/seasons?extended=episodes' + data = yield build_uri(self.ext + '/seasons', extended='episodes') self._seasons = [] for season in data: # Prepare episodes @@ -463,7 +437,7 @@ def last_episode(self): is found, `None` will be returned. """ if self._last_episode is None: - data = yield self.ext + '/last_episode?extended=full' + data = yield build_uri(self.ext + '/last_episode', extended='full') self._last_episode = data and TVEpisode(show=self.title, show_id=self.trakt, **data) yield self._last_episode @@ -475,7 +449,7 @@ def next_episode(self): is found, `None` will be returned. """ if self._next_episode is None: - data = yield self.ext + '/next_episode?extended=full' + data = yield build_uri(self.ext + '/next_episode', extended='full') self._next_episode = data and TVEpisode(show=self.title, show_id=self.trakt, **data) yield self._next_episode @@ -579,7 +553,8 @@ def __init__(self, show, season=1, slug=None, episodes=None, show_id=None, **kwa self.show_id = show_id self.season = season self.slug = slug or slugify(show) - self.ext = 'shows/{id}/seasons/{season}'.format(id=self.slug, season=season) + self.ext = build_uri('shows/{id}/seasons/{season}', id=self.slug, + season=season) self._comments = self._ratings = None self._episodes = self._build_episodes(episodes) if episodes else None @@ -662,9 +637,9 @@ def _episode_getter(self, episode): :param episode: An int corresponding to the number of the episode we're trying to retrieve """ - episode_extension = '/episodes/{}?extended=full'.format(episode) try: - data = yield self.ext + episode_extension + data = yield build_uri(self.ext + '/episodes/{episode}', + episode=episode, extended='full') yield TVEpisode(show=self.show, **data) except NotFoundException: yield None @@ -777,18 +752,17 @@ def ext(self): show_id = getattr(self, "show_id", None) if not show_id: show_id = slugify(self.show) - return 'shows/{id}/seasons/{season}/episodes/{episode}'.format( - id=show_id, season=self.season, episode=self.number - ) + return build_uri('shows/{id}/seasons/{season}/episodes/{episode}', + id=show_id, season=self.season, episode=self.number) @property def ext_full(self): - return self.ext + '?extended=full' + return build_uri(self.ext, extended='full') @property def images_ext(self): """Uri to retrieve additional image information""" - return self.ext + '?extended=images' + return build_uri(self.ext, extended='images') @staticmethod def search(title, year=None): diff --git a/trakt/users.py b/trakt/users.py index 9e35d52..e7ca12e 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -475,8 +475,9 @@ def movie_collection(self): Protected users won't return any data unless you are friends. """ if self._movie_collection is None: - ext = 'users/{username}/collection/movies?extended=metadata' - data = yield ext.format(username=slugify(self.username)) + data = yield build_uri('users/{username}/collection/movies', + username=slugify(self.username), + extended='metadata') self._movie_collection = [] for movie in data: mov = movie.pop('movie') @@ -491,8 +492,9 @@ def show_collection(self): Protected users won't return any data unless you are friends. """ if self._show_collection is None: - ext = 'users/{username}/collection/shows?extended=metadata' - data = yield ext.format(username=slugify(self.username)) + data = yield build_uri('users/{username}/collection/shows', + username=slugify(self.username), + extended='metadata') self._show_collection = [] for show_data in data: show_item = show_data.pop('show') @@ -647,8 +649,7 @@ def get_liked_lists(self, list_type=None, limit=None): if list_type is not None: uri += f'/{list_type}' - if limit is not None: - uri += f'?limit={limit}' + uri = build_uri(uri, limit=limit) data = yield uri yield data diff --git a/trakt/utils.py b/trakt/utils.py index e7806c3..3c8537c 100644 --- a/trakt/utils.py +++ b/trakt/utils.py @@ -88,12 +88,13 @@ def _validate_pagination_param(name, value): return value -def build_uri(uri, page=None, limit=None, **params): +def build_uri(uri, page=None, limit=None, extended=None, **params): """Format *uri* and append pagination query parameters. ``page`` and ``limit`` are validated as positive integers and become query parameters. Remaining keyword arguments are applied via ``str.format`` on - *uri*; any ``None`` values are dropped before formatting (so a missing + *uri*; ``extended`` is appended as a query parameter when provided. + Any ``None`` values are dropped before formatting (so a missing placeholder will raise ``KeyError``). """ params = {key: value for key, value in params.items() if value is not None} @@ -104,6 +105,8 @@ def build_uri(uri, page=None, limit=None, **params): query.append(('page', _validate_pagination_param('page', page))) if limit is not None: query.append(('limit', _validate_pagination_param('limit', limit))) + if extended: + query.append(('extended', extended)) if query: uri += ('&' if '?' in uri else '?') + urlencode(query)