From 676cbb1aaf9c8d19d207ec9575ffaa9665d8e710 Mon Sep 17 00:00:00 2001 From: Raymond Wagner Date: Thu, 3 May 2012 02:43:07 -0400 Subject: [PATCH] Clean up __repr__ methods, and impose soft 80-character line limit. --- setup.py | 2 +- tmdb3/locales.py | 3 +- tmdb3/tmdb_api.py | 169 +++++++++++++++++++++++----------------------- tmdb3/util.py | 26 +++++-- 4 files changed, 108 insertions(+), 92 deletions(-) diff --git a/setup.py b/setup.py index a4023a2bebe..9a391022f9f 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ setup( name='tmdb3', - version='0.3.4', + version='0.6.1', description='TheMovieDB.org APIv3 interface', long_description="Object-oriented interface to TheMovieDB.org's v3 API.", packages=['tmdb3'] diff --git a/tmdb3/locales.py b/tmdb3/locales.py index bb1c0f40a91..1c41983bc6c 100644 --- a/tmdb3/locales.py +++ b/tmdb3/locales.py @@ -46,7 +46,8 @@ def getstored(cls, key): try: return cls._stored[key.lower()] except: - raise TMDBLocaleError("'{0}' is not a known valid {1} code.".format(key, cls.__name__)) + raise TMDBLocaleError("'{0}' is not a known valid {1} code."\ + .format(key, cls.__name__)) class Language( LocaleBase ): __slots__ = ['ISO639_1', 'ISO639_2', 'ISO639_2B', 'englishname', diff --git a/tmdb3/tmdb_api.py b/tmdb3/tmdb_api.py index 4e01d1941f0..c698ec654cd 100644 --- a/tmdb3/tmdb_api.py +++ b/tmdb3/tmdb_api.py @@ -46,7 +46,7 @@ # 0.6.1 Add adult filtering for people searches from request import set_key, Request -from util import Datapoint, Datalist, Datadict, Element +from util import Datapoint, Datalist, Datadict, Element, NameRepr, SearchRepr from pager import PagedRequest from locales import get_locale, set_locale from tmdb_auth import get_session, set_session @@ -68,7 +68,7 @@ def _populate(self): return Request('configuration') Configuration = Configuration() -class Account( Element ): +class Account( NameRepr, Element ): def _populate(self): return Request('account', session_id=self._session.sessionid) @@ -83,15 +83,12 @@ def _populate(self): def locale(self): return get_locale(self.language, self.country) - def __repr__(self): - return '<{0} "{1.name}">'.format(self.__class__.__name__, self) - def searchMovie(query, locale=None, adult=False): return MovieSearchResult( Request('search/movie', query=query, include_adult=adult), locale=locale) -class MovieSearchResult( PagedRequest ): +class MovieSearchResult( SearchRepr, PagedRequest ): """Stores a list of search matches.""" _name = None def __init__(self, request, locale=None): @@ -101,23 +98,17 @@ def __init__(self, request, locale=None): request.new(language=locale.language), lambda x: Movie(raw=x, locale=locale)) - def __repr__(self): - name = self._name if self._name else self._request._kwargs['query'] - return u"".format(name) - def searchPerson(query, adult=False): return PeopleSearchResult(Request('search/person', query=query, include_adult=adult)) -class PeopleSearchResult( PagedRequest ): +class PeopleSearchResult( SearchRepr, PagedRequest ): """Stores a list of search matches.""" + _name = None def __init__(self, request): super(PeopleSearchResult, self).__init__(request, lambda x: Person(raw=x)) - def __repr__(self): - return u"".format(self._request._kwargs['query']) - class Image( Element ): filename = Datapoint('file_path', initarg=1, handler=lambda x: x.lstrip('/')) @@ -146,6 +137,7 @@ def __eq__(self, other): return self.language == other.language def __repr__(self): + # BASE62 encoded filename, no need to worry about unicode return u"<{0.__class__.__name__} '{0.filename}'>".format(self) class Backdrop( Image ): @@ -175,6 +167,10 @@ def __gt__(self, other): def __eq__(self, other): return self.country == other.country + def __repr__(self): + return u"<{0.__class__.__name__} '{0.title}' ({0.country})>"\ + .format(self).encode('utf-8') + class Person( Element ): id = Datapoint('id', initarg=1) name = Datapoint('name') @@ -188,18 +184,21 @@ class Person( Element ): aliases = Datalist('also_known_as') def __repr__(self): - return u"<{0} '{1.name}' at {2}>".\ - format(self.__class__.__name__, self, hex(id(self))) + return u"<{0.__class__.__name__} '{0.name}'>"\ + .format(self).encode('utf-8') def _populate(self): return Request('person/{0}'.format(self.id)) def _populate_credits(self): - return Request('person/{0}/credits'.format(self.id), language=self._locale.language) + return Request('person/{0}/credits'.format(self.id), \ + language=self._locale.language) def _populate_images(self): return Request('person/{0}/images'.format(self.id)) - roles = Datalist('cast', handler=lambda x: ReverseCast(raw=x), poller=_populate_credits) - crew = Datalist('crew', handler=lambda x: ReverseCrew(raw=x), poller=_populate_credits) + roles = Datalist('cast', handler=lambda x: ReverseCast(raw=x), \ + poller=_populate_credits) + crew = Datalist('crew', handler=lambda x: ReverseCrew(raw=x), \ + poller=_populate_credits) profiles = Datalist('profiles', handler=Profile, poller=_populate_images) class Cast( Person ): @@ -207,29 +206,31 @@ class Cast( Person ): order = Datapoint('order') def __repr__(self): - return u"<{0} '{1.name}' as '{1.character}'>".\ - format(self.__class__.__name__, self) + return u"<{0.__class__.__name__} '{0.name}' as '{0.character}'>"\ + .format(self).encode('utf-8') class Crew( Person ): job = Datapoint('job') department = Datapoint('department') def __repr__(self): - return u"<{0.__class__.__name__} '{1.name}','{1.job}'>".format(self) + return u"<{0.__class__.__name__} '{0.name}','{0.job}'>"\ + .format(self).encode('utf-8') class Keyword( Element ): id = Datapoint('id') name = Datapoint('name') def __repr__(self): - return u"<{0.__class__.__name__} {0.name}>".format(self) + return u"<{0.__class__.__name__} {0.name}>".format(self).encode('utf-8') class Release( Element ): certification = Datapoint('certification') country = Datapoint('iso_3166_1') releasedate = Datapoint('release_date', handler=process_date) def __repr__(self): - return u"".format(self) + return u"<{0.__class__.__name__} {0.country}, {0.releasedate}>"\ + .format(self).encode('utf-8') class Trailer( Element ): name = Datapoint('name') @@ -241,6 +242,7 @@ def geturl(self): return "http://www.youtube.com/watch?v={0}".format(self.source) def __repr__(self): + # modified BASE64 encoding, no need to worry about unicode return u"<{0.__class__.__name__} '{0.name}'>".format(self) class AppleTrailer( Element ): @@ -265,16 +267,14 @@ class Translation( Element ): englishname = Datapoint('english_name') def __repr__(self): - return u"<{0.__class__.__name__} '{0.name}' ({0.language})>".format(self) + return u"<{0.__class__.__name__} '{0.name}' ({0.language})>"\ + .format(self).encode('utf-8') -class Genre( Element ): +class Genre( NameRepr, Element ): id = Datapoint('id') name = Datapoint('name') - def __repr__(self): - return u"<{0.__class__.__name__} '{0.name}'>".format(self) - -class Studio( Element ): +class Studio( NameRepr, Element ): id = Datapoint('id', initarg=1) name = Datapoint('name') description = Datapoint('description') @@ -282,39 +282,33 @@ class Studio( Element ): logo = Datapoint('logo_path', handler=Logo, raw=False) # FIXME: manage not-yet-defined handlers in a way that will propogate # locale information properly - parent = Datapoint('parent_company', handler=lambda x: Studio(raw=x)) - - def __repr__(self): - return u"<{0.__class__.__name__} '{0.name}'>".format(self) + parent = Datapoint('parent_company', \ + handler=lambda x: Studio(raw=x)) def _populate(self): return Request('company/{0}'.format(self.id)) def _populate_movies(self): - return Request('company/{0}/movies'.format(self.id), language=self._locale.language) + return Request('company/{0}/movies'.format(self.id), \ + language=self._locale.language) # FIXME: add a cleaner way of adding types with no additional processing @property def movies(self): if 'movies' not in self._data: - search = MovieSearchResult(self._populate_movies(), locale=self._locale) + search = MovieSearchResult(self._populate_movies(), \ + locale=self._locale) search._name = "{0.name} Movies".format(self) self._data['movies'] = search return self._data['movies'] -class Country( Element ): +class Country( NameRepr, Element ): code = Datapoint('iso_3166_1') name = Datapoint('name') - def __repr__(self): - return u"<{0.__class__.__name__} '{0.name}'>".format(self) - -class Language( Element ): +class Language( NameRepr, Element ): code = Datapoint('iso_639_1') name = Datapoint('name') - def __repr__(self): - return u"<{0.__class__.__name__} '{0.name}'>".format(self) - class Movie( Element ): @classmethod def latest(cls): @@ -405,37 +399,54 @@ def fromIMDB(cls, imdbid, locale=None): languages = Datalist('spoken_languages', handler=Language) def _populate(self): - return Request('movie/{0}'.format(self.id), language=self._locale.language) + return Request('movie/{0}'.format(self.id), \ + language=self._locale.language) def _populate_titles(self): - kwargs = {'country':self._locale.country} if not self._locale.fallthrough else {} + kwargs = {} + if not self._locale.fallthrough: + kwargs['country'] = self._locale.country return Request('movie/{0}/alternative_titles'.format(self.id), **kwargs) def _populate_cast(self): return Request('movie/{0}/casts'.format(self.id)) def _populate_images(self): - kwargs = {'language':self._locale.language} if not self._locale.fallthrough else {} + kwargs = {} + if not self._locale.fallthrough: + kwargs['country'] = self._locale.country return Request('movie/{0}/images'.format(self.id), **kwargs) def _populate_keywords(self): return Request('movie/{0}/keywords'.format(self.id)) def _populate_releases(self): return Request('movie/{0}/releases'.format(self.id)) def _populate_trailers(self): - return Request('movie/{0}/trailers'.format(self.id), language=self._locale.language) + return Request('movie/{0}/trailers'.format(self.id), \ + language=self._locale.language) def _populate_translations(self): return Request('movie/{0}/translations'.format(self.id)) - alternate_titles = Datalist('titles', handler=AlternateTitle, poller=_populate_titles, sort=True) - cast = Datalist('cast', handler=Cast, poller=_populate_cast, sort='order') + alternate_titles = Datalist('titles', handler=AlternateTitle, \ + poller=_populate_titles, sort=True) + cast = Datalist('cast', handler=Cast, \ + poller=_populate_cast, sort='order') crew = Datalist('crew', handler=Crew, poller=_populate_cast) - backdrops = Datalist('backdrops', handler=Backdrop, poller=_populate_images, sort=True) - posters = Datalist('posters', handler=Poster, poller=_populate_images, sort=True) - keywords = Datalist('keywords', handler=Keyword, poller=_populate_keywords) - releases = Datadict('countries', handler=Release, poller=_populate_releases, attr='country') - youtube_trailers = Datalist('youtube', handler=YoutubeTrailer, poller=_populate_trailers) - apple_trailers = Datalist('quicktime', handler=AppleTrailer, poller=_populate_trailers) - translations = Datalist('translations', handler=Translation, poller=_populate_translations) + backdrops = Datalist('backdrops', handler=Backdrop, \ + poller=_populate_images, sort=True) + posters = Datalist('posters', handler=Poster, \ + poller=_populate_images, sort=True) + keywords = Datalist('keywords', handler=Keyword, \ + poller=_populate_keywords) + releases = Datadict('countries', handler=Release, \ + poller=_populate_releases, attr='country') + youtube_trailers = Datalist('youtube', handler=YoutubeTrailer, \ + poller=_populate_trailers) + apple_trailers = Datalist('quicktime', handler=AppleTrailer, \ + poller=_populate_trailers) + translations = Datalist('translations', handler=Translation, \ + poller=_populate_translations) def setFavorite(self, value): - req = Request('account/{0}/favorite'.format(Account(session=self._session).id), session_id=self._session.sessionid) + req = Request('account/{0}/favorite'.format(\ + Account(session=self._session).id), + session_id=self._session.sessionid) req.add_data({'movie_id':self.id, 'favorite':str(bool(value)).lower()}) req.lifetime = 0 req.readJSON() @@ -443,12 +454,13 @@ def setFavorite(self, value): def setRating(self, value): if not (0 <= value <= 10): raise TMDBError("Ratings must be between '0' and '10'.") - req = Request('movie/{0}/favorite'.format(self.id), session_id=self._session.sessionid) + req = Request('movie/{0}/favorite'.format(self.id), \ + session_id=self._session.sessionid) req.lifetime = 0 req.add_data({'value':value}) req.readJSON() - def __repr__(self): + def _printable_name(self): if self.title is not None: s = u"'{0}'".format(self.title) elif self.originaltitle is not None: @@ -457,38 +469,28 @@ def __repr__(self): s = u"'No Title'" if self.releasedate: s = u"{0} ({1})".format(s, self.releasedate.year) - return u"<{0} {1}>".format(self.__class__.__name__, s).encode('utf-8') + return s + + def __repr__(self): + return u"<{0} {1}>".format(self.__class__.__name__,\ + self._printable_name()).encode('utf-8') class ReverseCast( Movie ): character = Datapoint('character') def __repr__(self): - if self.title is not None: - s = u"'{0}'".format(self.title) - elif self.originaltitle is not None: - s = u"'{0}'".format(self.originaltitle) - else: - s = u"'No Title'" - if self.releasedate: - s = u"{0} ({1})".format(s, self.releasedate.year) - return u"<{0.__class__.__name__} '{0.character}' on {1}>".format(self, s).encode('utf-8') + return u"<{0.__class__.__name__} '{0.character}' on {1}>"\ + .format(self, self._printable_name()).encode('utf-8') class ReverseCrew( Movie ): department = Datapoint('department') job = Datapoint('job') def __repr__(self): - if self.title is not None: - s = u"'{0}'".format(self.title) - elif self.originaltitle is not None: - s = u"'{0}'".format(self.originaltitle) - else: - s = u"'No Title'" - if self.releasedate: - s = u"{0} ({1})".format(s, self.releasedate.year) - return u"<{0.__class__.__name__} '{0.job}' for {1}>".format(self, s).encode('utf-8') + return u"<{0.__class__.__name__} '{0.job}' for {1}>"\ + .format(self, self._printable_name()).encode('utf-8') -class Collection( Element ): +class Collection( NameRepr, Element ): id = Datapoint('id', initarg=1) name = Datapoint('name') backdrop = Datapoint('backdrop_path', handler=Backdrop, raw=False) @@ -496,11 +498,8 @@ class Collection( Element ): members = Datalist('parts', handler=Movie, sort='releasedate') def _populate(self): - return Request('collection/{0}'.format(self.id), language=self._locale.language) - - def __repr__(self): - return u"<{0.__class__.__name__} '{0.name}'>".format(self).encode('utf-8') - return u"<{0} {1}>".format(self.__class__.__name__, s).encode('utf-8') + return Request('collection/{0}'.format(self.id), \ + language=self._locale.language) if __name__ == '__main__': set_key('c27cb71cff5bd76e1a7a009380562c62') #MythTV API Key diff --git a/tmdb3/util.py b/tmdb3/util.py index 27cb91a6dd0..1c3209e0fe2 100644 --- a/tmdb3/util.py +++ b/tmdb3/util.py @@ -10,6 +10,21 @@ from locales import get_locale from tmdb_auth import get_session +class NameRepr( object ): + """Mixin for __repr__ methods using 'name' attribute.""" + def __repr__(self): + return u"<{0.__class__.__name__} '{0.name}'>"\ + .format(self).encode('utf-8') + +class SearchRepr( object ): + """ + Mixin for __repr__ methods for classes with '_name' and + '_request' attributes. + """ + def __repr__(self): + name = self._name if self._name else self._request._kwargs['query'] + return u"".format(name).encode('utf-8') + class Poller( object ): """ Wrapper for an optional callable to populate an Element derived class @@ -91,10 +106,10 @@ def __init__(self, field, initarg=None, handler=None, poller=None, """ This defines how the dictionary value is to be processed by the poller field -- defines the dictionary key that filters what data this uses - initarg -- (optional) specifies that this field must be supplied when - creating a new instance of the Element class this definition - is mapped to. Takes an integer for the order it should be - used in the input arguments + initarg -- (optional) specifies that this field must be supplied + when creating a new instance of the Element class this + definition is mapped to. Takes an integer for the order + it should be used in the input arguments handler -- (optional) callable used to process the received value before being stored in the Element object. poller -- (optional) callable to be used if data is requested and @@ -195,7 +210,8 @@ class Datadict( Data ): Response definition class for dictionary data This maps to a key in a JSON dictionary storing a dictionary of data """ - def __init__(self, field, handler=None, poller=None, raw=True, key=None, attr=None): + def __init__(self, field, handler=None, poller=None, raw=True, + key=None, attr=None): """ This defines how the dictionary value is to be processed by the poller field -- defines the dictionary key that filters what data this uses