diff --git a/trakt/core.py b/trakt/core.py index dfd11f9..0b26ce2 100644 --- a/trakt/core.py +++ b/trakt/core.py @@ -7,10 +7,10 @@ import os import sys import time -from collections import namedtuple from datetime import datetime, timedelta, timezone from functools import wraps from json import JSONDecodeError +from typing import NamedTuple from urllib.parse import urljoin import requests @@ -362,12 +362,34 @@ def init(*args, **kwargs): return auth_method.get(AUTH_METHOD, PIN_AUTH)(*args, **kwargs) -Airs = namedtuple('Airs', ['day', 'time', 'timezone']) -Alias = namedtuple('Alias', ['title', 'country']) -Genre = namedtuple('Genre', ['name', 'slug']) -Comment = namedtuple('Comment', ['id', 'parent_id', 'created_at', 'comment', - 'spoiler', 'review', 'replies', 'user', - 'updated_at', 'likes', 'user_rating']) +class Airs(NamedTuple): + day: str + time: str + timezone: str + + +class Alias(NamedTuple): + title: str + country: str + + +class Genre(NamedTuple): + name: str + slug: str + + +class Comment(NamedTuple): + id: str + parent_id: str + created_at: str + comment: str + spoiler: str + review: str + replies: str + user: str + updated_at: str + likes: str + user_rating: str def _validate_token(s): diff --git a/trakt/mixins.py b/trakt/mixins.py index 4b39195..d4b0d15 100644 --- a/trakt/mixins.py +++ b/trakt/mixins.py @@ -4,6 +4,23 @@ __author__ = 'Jon Nappi, Elan Ruusamäe' +def data_class_factory(data_class): + """ + A Mixin for inheriting @dataclass or NamedTuple, via composition rather inheritance. + """ + class DataClassMixinClass: + def __init__(self, **kwargs): + self.data = data_class(**kwargs) + + def __getattr__(self, item): + return getattr(self.data, item) + + return DataClassMixinClass + + +DataClassMixin = data_class_factory + + class IdsMixin: """ Provides Mixin to translate "ids" array @@ -14,8 +31,10 @@ class IdsMixin: __ids = ['imdb', 'slug', 'tmdb', 'trakt'] - def __init__(self): - self._ids = {} + def __init__(self, ids=None): + if ids is None: + ids = {} + self._ids = ids @property def ids(self): @@ -51,3 +70,11 @@ def tvdb(self): @property def tvrage(self): return self._ids.get('tvrage', None) + + @property + def slug(self): + return self._ids.get('slug', None) + + @slug.setter + def slug(self, value): + self._ids['slug'] = value diff --git a/trakt/movies.py b/trakt/movies.py index fea6372..4d299b7 100644 --- a/trakt/movies.py +++ b/trakt/movies.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """Interfaces to all of the Movie objects offered by the Trakt.tv API""" -from collections import namedtuple +from typing import NamedTuple from trakt.core import Alias, Comment, Genre, delete, get from trakt.mixins import IdsMixin @@ -16,8 +16,13 @@ 'trending_movies', 'updated_movies', 'Release', 'Movie', 'Translation'] -Translation = namedtuple('Translation', ['title', 'overview', 'tagline', - 'language']) + +# FIXME: same symbol in tv module +class Translation(NamedTuple): + title: str + overview: str + tagline: str + language: str @delete @@ -76,8 +81,12 @@ def updated_movies(timestamp=None): yield to_ret -Release = namedtuple('Release', ['country', 'certification', 'release_date', - 'note', 'release_type']) +class Release(NamedTuple): + country: str + certification: str + release_date: str + note: str + release_type: str class Movie(IdsMixin): diff --git a/trakt/tv.py b/trakt/tv.py index e6291a8..91db5b5 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Interfaces to all of the TV objects offered by the Trakt.tv API""" -from collections import namedtuple from datetime import datetime, timedelta +from typing import NamedTuple from urllib.parse import urlencode from trakt.core import Airs, Alias, Comment, Genre, delete, get @@ -22,7 +22,11 @@ 'TVSeason', 'Translation'] -Translation = namedtuple('Translation', ['title', 'overview', 'language']) +# FIXME: same symbol in movie module +class Translation(NamedTuple): + title: str + overview: str + language: str @delete diff --git a/trakt/users.py b/trakt/users.py index 90717ef..4a8b33e 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- """Interfaces to all of the User objects offered by the Trakt.tv API""" -from collections import namedtuple +from typing import Any, NamedTuple from trakt.core import delete, get, post -from trakt.mixins import IdsMixin +from trakt.mixins import DataClassMixin, IdsMixin from trakt.movies import Movie from trakt.people import Person from trakt.tv import TVEpisode, TVSeason, TVShow @@ -14,8 +14,10 @@ 'get_user_settings', 'unfollow'] -class Request(namedtuple('Request', ['id', 'requested_at', 'user'])): - __slots__ = () +class Request(NamedTuple): + id: int + user: Any + requested_at: str @post def approve(self): @@ -62,17 +64,30 @@ def unfollow(user_name): yield 'users/{username}/follow'.format(username=slugify(user_name)) -class UserList(namedtuple('UserList', ['name', 'description', 'privacy', - 'share_link', 'type', 'display_numbers', - 'allow_comments', 'sort_by', - 'sort_how', 'created_at', - 'updated_at', 'item_count', - 'comment_count', 'likes', 'ids', - 'user', 'creator']), IdsMixin): +class UserListTuple(NamedTuple): + name: str + description: str + privacy: str + share_link: str + type: str + display_numbers: bool + allow_comments: bool + sort_by: str + sort_how: str + created_at: str + updated_at: str + item_count: int + comment_count: int + likes: int + user: Any + creator: str + + +class UserList(DataClassMixin(UserListTuple), IdsMixin): """A list created by a Trakt.tv :class:`User`""" - def __init__(self, *args, ids=None, **kwargs): - super().__init__() + def __init__(self, ids=None, **kwargs): + super().__init__(**kwargs) self._ids = ids self._items = list() @@ -80,10 +95,6 @@ def __iter__(self): """Iterate over the items in this user list""" return self._items.__iter__() - @property - def slug(self): - return self._ids.get('slug', None) - @classmethod @post def create(cls, name, creator, description=None, privacy='private',