Changes of Revision 3

python-tvdb_api.changes Changed
x
 
1
@@ -1,4 +1,14 @@
2
 -------------------------------------------------------------------
3
+Thu Nov  1 16:49:30 UTC 2018 - Aliaksei Padvalski <avvissu@yandex.by>
4
+
5
+- Update to 2.0:
6
+  * Switch to TheTVDB new JSON based API - issue #57
7
+- Add support for Python3
8
+- Fix: non-executable-script
9
+- Update to description
10
+- Spec file cleanup
11
+
12
+-------------------------------------------------------------------
13
 Fri Apr 21 12:40:16 UTC 2017 - aloisio@gmx.com
14
 
15
 - Update to version 1.10
16
python-tvdb_api.spec Changed
91
 
1
@@ -1,6 +1,7 @@
2
 #
3
 # spec file for package python-tvdb_api
4
 #
5
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
6
 # Copyright (c) 2017 Packman Team <packman@links2linux.de>
7
 #
8
 # All modifications and additions to the file contributed by third parties
9
@@ -16,42 +17,60 @@
10
 #
11
 
12
 
13
-%define modname tvdb_api
14
+%{?!python_module:%define python_module() %{!?skip_python2:python-%{**}} %{!?skip_python3:python3-%{**}}}
15
 Name:           python-tvdb_api
16
-Version:        1.10
17
+Version:        2.0
18
 Release:        0
19
-Summary:        Python module to access the API from thetvdb.com
20
+Summary:        Interface to thetvdb.com
21
 # The UnLicense (https://unlicense.org)
22
 License:        SUSE-Permissive
23
 Group:          Productivity/Multimedia/Other
24
-Url:            https://github.com/dbr/tvdb_api/tree/master
25
-Source0:        https://files.pythonhosted.org/packages/source/t/%{modname}/%{modname}-%{version}.tar.gz
26
-BuildRequires:  python-devel
27
-BuildRequires:  python-setuptools
28
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
29
+URL:            https://github.com/dbr/tvdb_api
30
+Source0:        https://files.pythonhosted.org/packages/source/t/tvdb_api/tvdb_api-%{version}.tar.gz
31
+BuildRequires:  %{python_module devel}
32
+BuildRequires:  %{python_module rpm-macros}
33
+BuildRequires:  %{python_module setuptools}
34
+BuildRequires:  fdupes
35
+Requires:       python-requests-cache
36
 BuildArch:      noarch
37
-%py_requires
38
+%python_subpackages
39
 
40
 %description
41
-tvdb_api is an easy to use interface to thetvdb.com via python
42
+An easy to use API interface to TheTVDB.com.
43
 
44
 %prep
45
-%setup -q -n %{modname}-%{version}
46
-for file in {tvdb_cache,tvdb_api,tvdb_ui,tvdb_exceptions}
47
-do
48
-    sed -i "1d" $file.py
49
-done
50
+%setup -q -n tvdb_api-%{version}
51
 
52
 %build
53
-python setup.py build
54
+%python_build
55
 
56
 %install
57
-python setup.py install --root=%{buildroot} --prefix=%{_prefix}
58
+%python_install
59
+
60
+# Fix: non-executable-script
61
+%{python_expand \
62
+pushd %{buildroot}%{$python_sitelib}
63
+for _file in $(grep -rl '^\#\!\/'); do
64
+  find -name ${_file##*/} -type f -not -perm /111 -exec sed '/^\#\!\//d' -i {} +
65
+  find -name ${_file##*/} -type f -perm /111 -exec sed 's|#!%{_bindir}/env python|#!%__$python|' -i {} +
66
+done
67
+popd
68
+}
69
+
70
+%if 0%{?have_python2}
71
+%py_compile %{buildroot}%{python2_sitelib}
72
+%py_compile -O %{buildroot}%{python2_sitelib}
73
+%endif
74
+%if 0%{?have_python3}
75
+%py3_compile %{buildroot}%{python3_sitelib}
76
+%py3_compile -O %{buildroot}%{python3_sitelib}
77
+%endif
78
+#
79
+
80
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
81
 
82
-%files
83
-%defattr(-,root,root)
84
+%files %{python_files}
85
 %doc UNLICENSE readme.md
86
-%{python_sitelib}/tvdb_*.py*
87
-%{python_sitelib}/%{modname}-%{version}-py%{python_version}.egg-info
88
+%{python_sitelib}/*
89
 
90
 %changelog
91
tvdb_api-1.10.tar.gz/tvdb_cache.py Deleted
201
 
1
@@ -1,251 +0,0 @@
2
-#!/usr/bin/env python
3
-#encoding:utf-8
4
-#author:dbr/Ben
5
-#project:tvdb_api
6
-#repository:http://github.com/dbr/tvdb_api
7
-#license:unlicense (http://unlicense.org/)
8
-
9
-"""
10
-urllib2 caching handler
11
-Modified from http://code.activestate.com/recipes/491261/
12
-"""
13
-from __future__ import with_statement
14
-
15
-__author__ = "dbr/Ben"
16
-__version__ = "1.10"
17
-
18
-import os
19
-import time
20
-import errno
21
-import httplib
22
-import urllib2
23
-import StringIO
24
-from hashlib import md5
25
-from threading import RLock
26
-
27
-cache_lock = RLock()
28
-
29
-def locked_function(origfunc):
30
-    """Decorator to execute function under lock"""
31
-    def wrapped(*args, **kwargs):
32
-        cache_lock.acquire()
33
-        try:
34
-            return origfunc(*args, **kwargs)
35
-        finally:
36
-            cache_lock.release()
37
-    return wrapped
38
-
39
-def calculate_cache_path(cache_location, url):
40
-    """Checks if [cache_location]/[hash_of_url].headers and .body exist
41
-    """
42
-    thumb = md5(url).hexdigest()
43
-    header = os.path.join(cache_location, thumb + ".headers")
44
-    body = os.path.join(cache_location, thumb + ".body")
45
-    return header, body
46
-
47
-def check_cache_time(path, max_age):
48
-    """Checks if a file has been created/modified in the [last max_age] seconds.
49
-    False means the file is too old (or doesn't exist), True means it is
50
-    up-to-date and valid"""
51
-    if not os.path.isfile(path):
52
-        return False
53
-    cache_modified_time = os.stat(path).st_mtime
54
-    time_now = time.time()
55
-    if cache_modified_time < time_now - max_age:
56
-        # Cache is old
57
-        return False
58
-    else:
59
-        return True
60
-
61
-@locked_function
62
-def exists_in_cache(cache_location, url, max_age):
63
-    """Returns if header AND body cache file exist (and are up-to-date)"""
64
-    hpath, bpath = calculate_cache_path(cache_location, url)
65
-    if os.path.exists(hpath) and os.path.exists(bpath):
66
-        return(
67
-            check_cache_time(hpath, max_age)
68
-            and check_cache_time(bpath, max_age)
69
-        )
70
-    else:
71
-        # File does not exist
72
-        return False
73
-
74
-@locked_function
75
-def store_in_cache(cache_location, url, response):
76
-    """Tries to store response in cache."""
77
-    hpath, bpath = calculate_cache_path(cache_location, url)
78
-    try:
79
-        outf = open(hpath, "wb")
80
-        headers = str(response.info())
81
-        outf.write(headers)
82
-        outf.close()
83
-
84
-        outf = open(bpath, "wb")
85
-        outf.write(response.read())
86
-        outf.close()
87
-    except IOError:
88
-        return True
89
-    else:
90
-        return False
91
-        
92
-@locked_function
93
-def delete_from_cache(cache_location, url):
94
-    """Deletes a response in cache."""
95
-    hpath, bpath = calculate_cache_path(cache_location, url)
96
-    try:
97
-        if os.path.exists(hpath):
98
-            os.remove(hpath)
99
-        if os.path.exists(bpath):
100
-            os.remove(bpath)
101
-    except IOError:
102
-        return True
103
-    else:
104
-        return False
105
-
106
-class CacheHandler(urllib2.BaseHandler):
107
-    """Stores responses in a persistant on-disk cache.
108
-
109
-    If a subsequent GET request is made for the same URL, the stored
110
-    response is returned, saving time, resources and bandwidth
111
-    """
112
-    @locked_function
113
-    def __init__(self, cache_location, max_age = 21600):
114
-        """The location of the cache directory"""
115
-        self.max_age = max_age
116
-        self.cache_location = cache_location
117
-        if not os.path.exists(self.cache_location):
118
-            try:
119
-                os.mkdir(self.cache_location)
120
-            except OSError, e:
121
-                if e.errno == errno.EEXIST and os.path.isdir(self.cache_location):
122
-                    # File exists, and it's a directory,
123
-                    # another process beat us to creating this dir, that's OK.
124
-                    pass
125
-                else:
126
-                    # Our target dir is already a file, or different error,
127
-                    # relay the error!
128
-                    raise
129
-
130
-    def default_open(self, request):
131
-        """Handles GET requests, if the response is cached it returns it
132
-        """
133
-        if request.get_method() is not "GET":
134
-            return None # let the next handler try to handle the request
135
-
136
-        if exists_in_cache(
137
-            self.cache_location, request.get_full_url(), self.max_age
138
-        ):
139
-            return CachedResponse(
140
-                self.cache_location,
141
-                request.get_full_url(),
142
-                set_cache_header = True
143
-            )
144
-        else:
145
-            return None
146
-
147
-    def http_response(self, request, response):
148
-        """Gets a HTTP response, if it was a GET request and the status code
149
-        starts with 2 (200 OK etc) it caches it and returns a CachedResponse
150
-        """
151
-        if (request.get_method() == "GET"
152
-            and str(response.code).startswith("2")
153
-        ):
154
-            if 'x-local-cache' not in response.info():
155
-                # Response is not cached
156
-                set_cache_header = store_in_cache(
157
-                    self.cache_location,
158
-                    request.get_full_url(),
159
-                    response
160
-                )
161
-            else:
162
-                set_cache_header = True
163
-
164
-            return CachedResponse(
165
-                self.cache_location,
166
-                request.get_full_url(),
167
-                set_cache_header = set_cache_header
168
-            )
169
-        else:
170
-            return response
171
-
172
-class CachedResponse(StringIO.StringIO):
173
-    """An urllib2.response-like object for cached responses.
174
-
175
-    To determine if a response is cached or coming directly from
176
-    the network, check the x-local-cache header rather than the object type.
177
-    """
178
-
179
-    @locked_function
180
-    def __init__(self, cache_location, url, set_cache_header=True):
181
-        self.cache_location = cache_location
182
-        hpath, bpath = calculate_cache_path(cache_location, url)
183
-
184
-        StringIO.StringIO.__init__(self, file(bpath, "rb").read())
185
-
186
-        self.url     = url
187
-        self.code    = 200
188
-        self.msg     = "OK"
189
-        headerbuf = file(hpath, "rb").read()
190
-        if set_cache_header:
191
-            headerbuf += "x-local-cache: %s\r\n" % (bpath)
192
-        self.headers = httplib.HTTPMessage(StringIO.StringIO(headerbuf))
193
-
194
-    def info(self):
195
-        """Returns headers
196
-        """
197
-        return self.headers
198
-
199
-    def geturl(self):
200
-        """Returns original URL
201
tvdb_api-1.10.tar.gz/PKG-INFO -> tvdb_api-2.0.tar.gz/PKG-INFO Changed
27
 
1
@@ -1,6 +1,6 @@
2
 Metadata-Version: 1.1
3
 Name: tvdb_api
4
-Version: 1.10
5
+Version: 2.0
6
 Summary: Interface to thetvdb.com
7
 Home-page: http://github.com/dbr/tvdb_api/tree/master
8
 Author: dbr/Ben
9
@@ -14,7 +14,7 @@
10
         >>> ep = t['My Name Is Earl'][1][22]
11
         >>> ep
12
         <Episode 01x22 - Stole a Badge>
13
-        >>> ep['episodename']
14
+        >>> ep['episodeName']
15
         u'Stole a Badge'
16
         
17
 Platform: UNKNOWN
18
@@ -27,6 +27,8 @@
19
 Classifier: Programming Language :: Python :: 2.7
20
 Classifier: Programming Language :: Python :: 3.3
21
 Classifier: Programming Language :: Python :: 3.4
22
+Classifier: Programming Language :: Python :: 3.5
23
+Classifier: Programming Language :: Python :: 3.6
24
 Classifier: Topic :: Multimedia
25
 Classifier: Topic :: Utilities
26
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
tvdb_api-1.10.tar.gz/Rakefile -> tvdb_api-2.0.tar.gz/Rakefile Changed
10
 
1
@@ -47,7 +47,7 @@
2
 end
3
 
4
 desc "Upload current version to PyPi"
5
-task :topypi do
6
+task :topypi => :test do
7
   cur_file = File.open("tvdb_api.py").read()
8
   tvdb_api_version = cur_file.scan(/__version__ = "(.*)"/)
9
   tvdb_api_version = tvdb_api_version[0][0]
10
tvdb_api-1.10.tar.gz/readme.md -> tvdb_api-2.0.tar.gz/readme.md Changed
19
 
1
@@ -65,7 +65,7 @@
2
 The data is stored in an attribute named `data`, within the Show instance:
3
 
4
     >>> t['scrubs'].data.keys()
5
-    ['networkid', 'rating', 'airs_dayofweek', 'contentrating', 'seriesname', 'id', 'airs_time', 'network', 'fanart', 'lastupdated', 'actors', 'ratingcount', 'status', 'added', 'poster', 'imdb_id', 'genre', 'banner', 'seriesid', 'language', 'zap2it_id', 'addedby', 'tms_wanted', 'firstaired', 'runtime', 'overview']
6
+    ['networkid', 'rating', 'airs_dayofweek', 'contentrating', 'seriesname', 'id', 'airs_time', 'network', 'fanart', 'lastupdated', 'actors', 'ratingcount', 'status', 'added', 'poster', 'tms_wanted_old', 'imdb_id', 'genre', 'banner', 'seriesid', 'language', 'zap2it_id', 'addedby', 'firstaired', 'runtime', 'overview']
7
 
8
 Although each element is also accessible via `t['scrubs']` for ease-of-use:
9
 
10
@@ -105,7 +105,7 @@
11
 Remember a simple list of actors is accessible via the default Show data:
12
 
13
     >>> t['scrubs']['actors']
14
-    u'|Zach Braff|Donald Faison|Sarah Chalke|Christa Miller|Aloma Wright|Robert Maschio|Sam Lloyd|Neil Flynn|Ken Jenkins|Judy Reyes|John C. McGinley|Travis Schuldt|Johnny Kastl|Heather Graham|Michael Mosley|Kerry Bish\xe9|Dave Franco|Eliza Coupe|'
15
+    u'|Zach Braff|Donald Faison|Sarah Chalke|Judy Reyes|John C. McGinley|Neil Flynn|Ken Jenkins|Christa Miller|Aloma Wright|Robert Maschio|Sam Lloyd|Travis Schuldt|Johnny Kastl|Heather Graham|Michael Mosley|Kerry Bish\xe9|Dave Franco|Eliza Coupe|'
16
 
17
 [tvdb]: http://thetvdb.com
18
 [tvnamer]: http://github.com/dbr/tvnamer
19
tvdb_api-1.10.tar.gz/setup.py -> tvdb_api-2.0.tar.gz/setup.py Changed
73
 
1
@@ -1,25 +1,34 @@
2
 import sys
3
 from setuptools import setup
4
+from setuptools.command.test import test as TestCommand
5
 
6
-IS_PY2 = sys.version_info[0] == 2
7
 
8
-_requirements = []
9
-if not IS_PY2:
10
-    _requirements.append('requests_cache')
11
+class PyTest(TestCommand):
12
+    user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]
13
 
14
-    # 'requests' is installed as requirement by requests-cache,
15
-    # commented out because it triggers a bug in setuptool:
16
-    # https://bitbucket.org/pypa/setuptools/issue/196/tests_require-pytest-pytest-cov-breaks
17
+    def initialize_options(self):
18
+        TestCommand.initialize_options(self)
19
+        self.pytest_args = []
20
 
21
+    def finalize_options(self):
22
+        TestCommand.finalize_options(self)
23
+        self.test_args = []
24
+        self.test_suite = True
25
 
26
+    def run_tests(self):
27
+        #import here, cause outside the eggs aren't loaded
28
+        import pytest
29
+        errno = pytest.main(self.pytest_args)
30
+        sys.exit(errno)
31
+
32
+
33
+_requirements = ['requests_cache', 'requests']
34
 _modules = ['tvdb_api', 'tvdb_ui', 'tvdb_exceptions']
35
-if IS_PY2:
36
-    _modules.append('tvdb_cache')
37
 
38
 
39
 setup(
40
 name = 'tvdb_api',
41
-version='1.10',
42
+version='2.0',
43
 
44
 author='dbr/Ben',
45
 description='Interface to thetvdb.com',
46
@@ -35,13 +44,16 @@
47
 >>> ep = t['My Name Is Earl'][1][22]
48
 >>> ep
49
 <Episode 01x22 - Stole a Badge>
50
->>> ep['episodename']
51
+>>> ep['episodeName']
52
 u'Stole a Badge'
53
 """,
54
 
55
 py_modules = _modules,
56
 install_requires = _requirements,
57
 
58
+tests_require=['pytest'],
59
+cmdclass = {'test': PyTest},
60
+
61
 classifiers=[
62
     "Intended Audience :: Developers",
63
     "Natural Language :: English",
64
@@ -52,6 +64,8 @@
65
     "Programming Language :: Python :: 2.7",
66
     "Programming Language :: Python :: 3.3",
67
     "Programming Language :: Python :: 3.4",
68
+    "Programming Language :: Python :: 3.5",
69
+    "Programming Language :: Python :: 3.6",
70
     "Topic :: Multimedia",
71
     "Topic :: Utilities",
72
     "Topic :: Software Development :: Libraries :: Python Modules",
73
tvdb_api-1.10.tar.gz/tests/test_tvdb_api.py -> tvdb_api-2.0.tar.gz/tests/test_tvdb_api.py Changed
201
 
1
@@ -11,75 +11,58 @@
2
 import os
3
 import sys
4
 import datetime
5
-import unittest
6
+import pytest
7
 
8
 # Force parent directory onto path
9
 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
10
 
11
 import tvdb_api
12
-import tvdb_ui
13
 from tvdb_api import (tvdb_shownotfound, tvdb_seasonnotfound,
14
-tvdb_episodenotfound, tvdb_attributenotfound)
15
+                      tvdb_episodenotfound, tvdb_attributenotfound)
16
 
17
 
18
-IS_PY2 = sys.version_info[0] == 2
19
-
20
-
21
-class test_tvdb_basic(unittest.TestCase):
22
+class TestTvdbBasic:
23
     # Used to store the cached instance of Tvdb()
24
     t = None
25
-    
26
-    def setUp(self):
27
-        if self.t is None:
28
-            self.__class__.t = tvdb_api.Tvdb(cache = True, banners = False)
29
-     
30
+
31
+    @classmethod
32
+    def setup_class(cls):
33
+        if cls.t is None:
34
+            cls.t = tvdb_api.Tvdb(cache=True, banners=False)
35
+
36
     def test_different_case(self):
37
         """Checks the auto-correction of show names is working.
38
         It should correct the weirdly capitalised 'sCruBs' to 'Scrubs'
39
         """
40
-        self.assertEquals(self.t['scrubs'][1][4]['episodename'], 'My Old Lady')
41
-        self.assertEquals(self.t['sCruBs']['seriesname'], 'Scrubs')
42
+        assert self.t['scrubs'][1][4]['episodeName'] == 'My Old Lady'
43
+        assert self.t['sCruBs']['seriesName'] == 'Scrubs'
44
 
45
     def test_spaces(self):
46
         """Checks shownames with spaces
47
         """
48
-        self.assertEquals(self.t['My Name Is Earl']['seriesname'], 'My Name Is Earl')
49
-        self.assertEquals(self.t['My Name Is Earl'][1][4]['episodename'], 'Faked His Own Death')
50
+        assert self.t['My Name Is Earl']['seriesName'] == 'My Name Is Earl'
51
+        assert self.t['My Name Is Earl'][1][4]['episodeName'] == 'Faked My Own Death'
52
 
53
     def test_numeric(self):
54
         """Checks numeric show names
55
         """
56
-        self.assertEquals(self.t['24'][2][20]['episodename'], 'Day 2: 3:00 A.M.-4:00 A.M.')
57
-        self.assertEquals(self.t['24']['seriesname'], '24')
58
+        assert self.t['24'][2][20]['episodeName'] == 'Day 2: 3:00 A.M. - 4:00 A.M.'
59
+        assert self.t['24']['seriesName'] == '24'
60
 
61
     def test_show_iter(self):
62
         """Iterating over a show returns each seasons
63
         """
64
-        self.assertEquals(
65
-            len(
66
-                [season for season in self.t['Life on Mars']]
67
-            ),
68
-            2
69
-        )
70
-    
71
+        assert len([season for season in self.t['Life on Mars']]) == 2
72
+
73
     def test_season_iter(self):
74
         """Iterating over a show returns episodes
75
         """
76
-        self.assertEquals(
77
-            len(
78
-                [episode for episode in self.t['Life on Mars'][1]]
79
-            ),
80
-            8
81
-        )
82
+        assert len([episode for episode in self.t['Life on Mars'][1]]) == 8
83
 
84
     def test_get_episode_overview(self):
85
         """Checks episode overview is retrieved correctly.
86
         """
87
-        self.assertEquals(
88
-            self.t['Battlestar Galactica (2003)'][1][6]['overview'].startswith(
89
-                'When a new copy of Doral, a Cylon who had been previously'),
90
-            True
91
-        )
92
+        assert self.t['Battlestar Galactica (2003)'][1][6]['overview'].startswith('When a new copy of Doral, a Cylon who had been previously') == True
93
 
94
     def test_get_parent(self):
95
         """Check accessing series from episode instance
96
@@ -88,329 +71,251 @@
97
         season = show[1]
98
         episode = show[1][1]
99
 
100
-        self.assertEquals(
101
-            season.show,
102
-            show
103
-        )
104
-
105
-        self.assertEquals(
106
-            episode.season,
107
-            season
108
-        )
109
-
110
-        self.assertEquals(
111
-            episode.season.show,
112
-            show
113
-        )
114
+        assert season.show == show
115
+        assert episode.season == season
116
+        assert episode.season.show == show
117
 
118
     def test_no_season(self):
119
         show = self.t['Katekyo Hitman Reborn']
120
         print(tvdb_api)
121
         print(show[1][1])
122
 
123
-class test_tvdb_errors(unittest.TestCase):
124
-    # Used to store the cached instance of Tvdb()
125
+
126
+class TestTvdbErrors:
127
     t = None
128
-    
129
-    def setUp(self):
130
-        if self.t is None:
131
-            self.__class__.t = tvdb_api.Tvdb(cache = True, banners = False)
132
+
133
+    @classmethod
134
+    def setup_class(cls):
135
+        if cls.t is None:
136
+            cls.t = tvdb_api.Tvdb(cache=True, banners=False)
137
 
138
     def test_seasonnotfound(self):
139
         """Checks exception is thrown when season doesn't exist.
140
         """
141
-        self.assertRaises(tvdb_seasonnotfound, lambda:self.t['CNNNN'][10][1])
142
+        with pytest.raises(tvdb_seasonnotfound):
143
+            self.t['CNNNN'][10]
144
 
145
     def test_shownotfound(self):
146
         """Checks exception is thrown when episode doesn't exist.
147
         """
148
-        self.assertRaises(tvdb_shownotfound, lambda:self.t['the fake show thingy'])
149
-    
150
+        with pytest.raises(tvdb_shownotfound):
151
+            self.t['the fake show thingy']
152
+
153
     def test_episodenotfound(self):
154
         """Checks exception is raised for non-existent episode
155
         """
156
-        self.assertRaises(tvdb_episodenotfound, lambda:self.t['Scrubs'][1][30])
157
+        with pytest.raises(tvdb_episodenotfound):
158
+            self.t['Scrubs'][1][30]
159
 
160
     def test_attributenamenotfound(self):
161
         """Checks exception is thrown for if an attribute isn't found.
162
         """
163
-        self.assertRaises(tvdb_attributenotfound, lambda:self.t['CNNNN'][1][6]['afakeattributething'])
164
-        self.assertRaises(tvdb_attributenotfound, lambda:self.t['CNNNN']['afakeattributething'])
165
+        with pytest.raises(tvdb_attributenotfound):
166
+            self.t['CNNNN'][1][6]['afakeattributething']
167
+            self.t['CNNNN']['afakeattributething']
168
 
169
-class test_tvdb_search(unittest.TestCase):
170
+
171
+class TestTvdbSearch:
172
     # Used to store the cached instance of Tvdb()
173
     t = None
174
-    
175
-    def setUp(self):
176
-        if self.t is None:
177
-            self.__class__.t = tvdb_api.Tvdb(cache = True, banners = False)
178
+
179
+    @classmethod
180
+    def setup_class(cls):
181
+        if cls.t is None:
182
+            cls.t = tvdb_api.Tvdb(cache=True, banners=False)
183
 
184
     def test_search_len(self):
185
         """There should be only one result matching
186
         """
187
-        self.assertEquals(len(self.t['My Name Is Earl'].search('Faked His Own Death')), 1)
188
+        assert len(self.t['My Name Is Earl'].search('Faked My Own Death')) == 1
189
 
190
     def test_search_checkname(self):
191
         """Checks you can get the episode name of a search result
192
         """
193
-        self.assertEquals(self.t['Scrubs'].search('my first')[0]['episodename'], 'My First Day')
194
-        self.assertEquals(self.t['My Name Is Earl'].search('Faked His Own Death')[0]['episodename'], 'Faked His Own Death')
195
-    
196
+        assert self.t['Scrubs'].search('my first')[0]['episodeName'] == 'My First Day'
197
+        assert self.t['My Name Is Earl'].search('Faked My Own Death')[0]['episodeName'] == 'Faked My Own Death'
198
+
199
     def test_search_multiresults(self):
200
         """Checks search can return multiple results
201
tvdb_api-1.10.tar.gz/tvdb_api.egg-info/PKG-INFO -> tvdb_api-2.0.tar.gz/tvdb_api.egg-info/PKG-INFO Changed
27
 
1
@@ -1,6 +1,6 @@
2
 Metadata-Version: 1.1
3
 Name: tvdb-api
4
-Version: 1.10
5
+Version: 2.0
6
 Summary: Interface to thetvdb.com
7
 Home-page: http://github.com/dbr/tvdb_api/tree/master
8
 Author: dbr/Ben
9
@@ -14,7 +14,7 @@
10
         >>> ep = t['My Name Is Earl'][1][22]
11
         >>> ep
12
         <Episode 01x22 - Stole a Badge>
13
-        >>> ep['episodename']
14
+        >>> ep['episodeName']
15
         u'Stole a Badge'
16
         
17
 Platform: UNKNOWN
18
@@ -27,6 +27,8 @@
19
 Classifier: Programming Language :: Python :: 2.7
20
 Classifier: Programming Language :: Python :: 3.3
21
 Classifier: Programming Language :: Python :: 3.4
22
+Classifier: Programming Language :: Python :: 3.5
23
+Classifier: Programming Language :: Python :: 3.6
24
 Classifier: Topic :: Multimedia
25
 Classifier: Topic :: Utilities
26
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
tvdb_api-1.10.tar.gz/tvdb_api.egg-info/SOURCES.txt -> tvdb_api-2.0.tar.gz/tvdb_api.egg-info/SOURCES.txt Changed
16
 
1
@@ -4,7 +4,6 @@
2
 readme.md
3
 setup.py
4
 tvdb_api.py
5
-tvdb_cache.py
6
 tvdb_exceptions.py
7
 tvdb_ui.py
8
 tests/gprof2dot.py
9
@@ -13,4 +12,5 @@
10
 tvdb_api.egg-info/PKG-INFO
11
 tvdb_api.egg-info/SOURCES.txt
12
 tvdb_api.egg-info/dependency_links.txt
13
+tvdb_api.egg-info/requires.txt
14
 tvdb_api.egg-info/top_level.txt
15
\ No newline at end of file
16
tvdb_api-2.0.tar.gz/tvdb_api.egg-info/requires.txt Added
4
 
1
@@ -0,0 +1,2 @@
2
+requests_cache
3
+requests
4
tvdb_api-1.10.tar.gz/tvdb_api.egg-info/top_level.txt -> tvdb_api-2.0.tar.gz/tvdb_api.egg-info/top_level.txt Changed
7
 
1
@@ -1,4 +1,3 @@
2
 tvdb_api
3
-tvdb_ui
4
 tvdb_exceptions
5
-tvdb_cache
6
+tvdb_ui
7
tvdb_api-1.10.tar.gz/tvdb_api.py -> tvdb_api-2.0.tar.gz/tvdb_api.py Changed
201
 
1
@@ -1,9 +1,9 @@
2
 #!/usr/bin/env python
3
-#encoding:utf-8
4
-#author:dbr/Ben
5
-#project:tvdb_api
6
-#repository:http://github.com/dbr/tvdb_api
7
-#license:unlicense (http://unlicense.org/)
8
+# encoding:utf-8
9
+# author:dbr/Ben
10
+# project:tvdb_api
11
+# repository:http://github.com/dbr/tvdb_api
12
+# license:unlicense (http://unlicense.org/)
13
 
14
 """Simple-to-use Python interface to The TVDB's API (thetvdb.com)
15
 
16
@@ -11,42 +11,38 @@
17
 
18
 >>> from tvdb_api import Tvdb
19
 >>> t = Tvdb()
20
->>> t['Lost'][4][11]['episodename']
21
+>>> t['Lost'][4][11]['episodeName']
22
 u'Cabin Fever'
23
 """
24
-__author__ = "dbr/Ben"
25
-__version__ = "1.10"
26
 
27
-import sys
28
+__author__ = "dbr/Ben"
29
+__version__ = "2.0"
30
 
31
-IS_PY2 = sys.version_info[0] == 2
32
 
33
+import sys
34
 import os
35
 import time
36
-if IS_PY2:
37
-    import urllib
38
-    import urllib2
39
-    from tvdb_cache import CacheHandler
40
-    from urllib import quote as url_quote
41
-else:
42
-    import requests
43
-    from urllib.parse import quote as url_quote
44
+import types
45
 import getpass
46
 import tempfile
47
 import warnings
48
 import logging
49
 import datetime
50
-import zipfile
51
+import hashlib
52
 
53
-try:
54
-    import xml.etree.cElementTree as ElementTree
55
-except ImportError:
56
-    import xml.etree.ElementTree as ElementTree
57
+import requests
58
+import requests_cache
59
+from requests_cache.backends.base import _to_bytes, _DEFAULT_HEADERS
60
 
61
-try:
62
-    import gzip
63
-except ImportError:
64
-    gzip = None
65
+
66
+IS_PY2 = sys.version_info[0] == 2
67
+
68
+if IS_PY2:
69
+    user_input = raw_input
70
+    from urllib import quote as url_quote
71
+else:
72
+    from urllib.parse import quote as url_quote
73
+    user_input = input
74
 
75
 
76
 if IS_PY2:
77
@@ -56,17 +52,217 @@
78
     int_types = int
79
     text_type = str
80
 
81
-
82
-from tvdb_ui import BaseUI, ConsoleUI
83
-from tvdb_exceptions import (tvdb_error, tvdb_userabort, tvdb_shownotfound,
84
-    tvdb_seasonnotfound, tvdb_episodenotfound, tvdb_attributenotfound)
85
-
86
 lastTimeout = None
87
 
88
+
89
 def log():
90
     return logging.getLogger("tvdb_api")
91
 
92
 
93
+## Exceptions
94
+
95
+class tvdb_exception(Exception):
96
+    """Any exception generated by tvdb_api
97
+    """
98
+    pass
99
+
100
+class tvdb_error(tvdb_exception):
101
+    """An error with thetvdb.com (Cannot connect, for example)
102
+    """
103
+    pass
104
+
105
+class tvdb_userabort(tvdb_exception):
106
+    """User aborted the interactive selection (via
107
+    the q command, ^c etc)
108
+    """
109
+    pass
110
+
111
+class tvdb_notauthorized(tvdb_exception):
112
+    """An authorization error with thetvdb.com
113
+    """
114
+    pass
115
+
116
+class tvdb_shownotfound(tvdb_exception):
117
+    """Show cannot be found on thetvdb.com (non-existant show)
118
+    """
119
+    pass
120
+
121
+class tvdb_seasonnotfound(tvdb_exception):
122
+    """Season cannot be found on thetvdb.com
123
+    """
124
+    pass
125
+
126
+class tvdb_episodenotfound(tvdb_exception):
127
+    """Episode cannot be found on thetvdb.com
128
+    """
129
+    pass
130
+
131
+class tvdb_resourcenotfound(tvdb_exception):
132
+    """Resource cannot be found on thetvdb.com
133
+    """
134
+    pass
135
+
136
+class tvdb_invalidlanguage(tvdb_exception):
137
+    """invalid language given on thetvdb.com
138
+    """
139
+    def __init__(self, value):
140
+        self.value = value
141
+
142
+    def __str__(self):
143
+        return repr(self.value)
144
+
145
+class tvdb_attributenotfound(tvdb_exception):
146
+    """Raised if an episode does not have the requested
147
+    attribute (such as a episode name)
148
+    """
149
+    pass
150
+
151
+
152
+## UI
153
+
154
+class BaseUI(object):
155
+    """Base user interface for Tvdb show selection.
156
+
157
+    Selects first show.
158
+
159
+    A UI is a callback. A class, it's __init__ function takes two arguments:
160
+
161
+    - config, which is the Tvdb config dict, setup in tvdb_api.py
162
+    - log, which is Tvdb's logger instance (which uses the logging module). You can
163
+    call log.info() log.warning() etc
164
+
165
+    It must have a method "selectSeries", this is passed a list of dicts, each dict
166
+    contains the the keys "name" (human readable show name), and "sid" (the shows
167
+    ID as on thetvdb.com). For example:
168
+
169
+    [{'name': u'Lost', 'sid': u'73739'},
170
+     {'name': u'Lost Universe', 'sid': u'73181'}]
171
+
172
+    The "selectSeries" method must return the appropriate dict, or it can raise
173
+    tvdb_userabort (if the selection is aborted), tvdb_shownotfound (if the show
174
+    cannot be found).
175
+
176
+    A simple example callback, which returns a random series:
177
+
178
+    >>> import random
179
+    >>> from tvdb_ui import BaseUI
180
+    >>> class RandomUI(BaseUI):
181
+    ...    def selectSeries(self, allSeries):
182
+    ...            import random
183
+    ...            return random.choice(allSeries)
184
+
185
+    Then to use it..
186
+
187
+    >>> from tvdb_api import Tvdb
188
+    >>> t = Tvdb(custom_ui = RandomUI)
189
+    >>> random_matching_series = t['Lost']
190
+    >>> type(random_matching_series)
191
+    <class 'tvdb_api.Show'>
192
+    """
193
+    def __init__(self, config, log = None):
194
+        self.config = config
195
+        if log is not None:
196
+            warnings.warn("the UI's log parameter is deprecated, instead use\n"
197
+                "use import logging; logging.getLogger('ui').info('blah')\n"
198
+                "The self.log attribute will be removed in the next version")
199
+            self.log = logging.getLogger(__name__)
200
+
201
tvdb_api-1.10.tar.gz/tvdb_exceptions.py -> tvdb_api-2.0.tar.gz/tvdb_exceptions.py Changed
59
 
1
@@ -9,44 +9,20 @@
2
 """
3
 
4
 __author__ = "dbr/Ben"
5
-__version__ = "1.10"
6
+__version__ = "2.0"
7
 
8
-__all__ = ["tvdb_error", "tvdb_userabort", "tvdb_shownotfound",
9
-"tvdb_seasonnotfound", "tvdb_episodenotfound", "tvdb_attributenotfound"]
10
+import logging
11
 
12
-class tvdb_exception(Exception):
13
-    """Any exception generated by tvdb_api
14
-    """
15
-    pass
16
+__all__ = ["tvdb_error", "tvdb_userabort", "tvdb_notauthorized", "tvdb_shownotfound",
17
+"tvdb_seasonnotfound", "tvdb_episodenotfound", "tvdb_attributenotfound",
18
+"tvdb_resourcenotfound", "tvdb_invalidlanguage"]
19
 
20
-class tvdb_error(tvdb_exception):
21
-    """An error with thetvdb.com (Cannot connect, for example)
22
-    """
23
-    pass
24
+logging.getLogger(__name__).warning(
25
+    "tvdb_exceptions module is deprecated - use classes directly from tvdb_api instead")
26
 
27
-class tvdb_userabort(tvdb_exception):
28
-    """User aborted the interactive selection (via
29
-    the q command, ^c etc)
30
-    """
31
-    pass
32
-
33
-class tvdb_shownotfound(tvdb_exception):
34
-    """Show cannot be found on thetvdb.com (non-existant show)
35
-    """
36
-    pass
37
-
38
-class tvdb_seasonnotfound(tvdb_exception):
39
-    """Season cannot be found on thetvdb.com
40
-    """
41
-    pass
42
-
43
-class tvdb_episodenotfound(tvdb_exception):
44
-    """Episode cannot be found on thetvdb.com
45
-    """
46
-    pass
47
-
48
-class tvdb_attributenotfound(tvdb_exception):
49
-    """Raised if an episode does not have the requested
50
-    attribute (such as a episode name)
51
-    """
52
-    pass
53
+from tvdb_api import (
54
+    tvdb_error, tvdb_userabort, tvdb_notauthorized, tvdb_shownotfound,
55
+    tvdb_seasonnotfound, tvdb_episodenotfound,
56
+    tvdb_resourcenotfound, tvdb_invalidlanguage,
57
+    tvdb_attributenotfound
58
+)
59
tvdb_api-1.10.tar.gz/tvdb_ui.py -> tvdb_api-2.0.tar.gz/tvdb_ui.py Changed
169
 
1
@@ -5,45 +5,9 @@
2
 #repository:http://github.com/dbr/tvdb_api
3
 #license:unlicense (http://unlicense.org/)
4
 
5
-"""Contains included user interfaces for Tvdb show selection.
6
-
7
-A UI is a callback. A class, it's __init__ function takes two arguments:
8
-
9
-- config, which is the Tvdb config dict, setup in tvdb_api.py
10
-- log, which is Tvdb's logger instance (which uses the logging module). You can
11
-call log.info() log.warning() etc
12
-
13
-It must have a method "selectSeries", this is passed a list of dicts, each dict
14
-contains the the keys "name" (human readable show name), and "sid" (the shows
15
-ID as on thetvdb.com). For example:
16
-
17
-[{'name': u'Lost', 'sid': u'73739'},
18
- {'name': u'Lost Universe', 'sid': u'73181'}]
19
-
20
-The "selectSeries" method must return the appropriate dict, or it can raise
21
-tvdb_userabort (if the selection is aborted), tvdb_shownotfound (if the show
22
-cannot be found).
23
-
24
-A simple example callback, which returns a random series:
25
-
26
->>> import random
27
->>> from tvdb_ui import BaseUI
28
->>> class RandomUI(BaseUI):
29
-...    def selectSeries(self, allSeries):
30
-...            import random
31
-...            return random.choice(allSeries)
32
-
33
-Then to use it..
34
-
35
->>> from tvdb_api import Tvdb
36
->>> t = Tvdb(custom_ui = RandomUI)
37
->>> random_matching_series = t['Lost']
38
->>> type(random_matching_series)
39
-<class 'tvdb_api.Show'>
40
-"""
41
 
42
 __author__ = "dbr/Ben"
43
-__version__ = "1.10"
44
+__version__ = "2.0"
45
 
46
 import sys
47
 import logging
48
@@ -51,117 +15,7 @@
49
 
50
 from tvdb_exceptions import tvdb_userabort
51
 
52
+logging.getLogger(__name__).warning(
53
+    "tvdb_ui module is deprecated - use classes directly from tvdb_api instead")
54
 
55
-IS_PY2 = sys.version_info[0] == 2
56
-
57
-if IS_PY2:
58
-    user_input = raw_input
59
-else:
60
-    user_input = input
61
-
62
-
63
-def log():
64
-    return logging.getLogger(__name__)
65
-
66
-class BaseUI:
67
-    """Default non-interactive UI, which auto-selects first results
68
-    """
69
-    def __init__(self, config, log = None):
70
-        self.config = config
71
-        if log is not None:
72
-            warnings.warn("the UI's log parameter is deprecated, instead use\n"
73
-                "use import logging; logging.getLogger('ui').info('blah')\n"
74
-                "The self.log attribute will be removed in the next version")
75
-            self.log = logging.getLogger(__name__)
76
-
77
-    def selectSeries(self, allSeries):
78
-        return allSeries[0]
79
-
80
-
81
-class ConsoleUI(BaseUI):
82
-    """Interactively allows the user to select a show from a console based UI
83
-    """
84
-
85
-    def _displaySeries(self, allSeries, limit = 6):
86
-        """Helper function, lists series with corresponding ID
87
-        """
88
-        if limit is not None:
89
-            toshow = allSeries[:limit]
90
-        else:
91
-            toshow = allSeries
92
-
93
-        print("TVDB Search Results:")
94
-        for i, cshow in enumerate(toshow):
95
-            i_show = i + 1 # Start at more human readable number 1 (not 0)
96
-            log().debug('Showing allSeries[%s], series %s)' % (i_show, allSeries[i]['seriesname']))
97
-            if i == 0:
98
-                extra = " (default)"
99
-            else:
100
-                extra = ""
101
-
102
-            output = "%s -> %s [%s] # http://thetvdb.com/?tab=series&id=%s&lid=%s%s" % (
103
-                i_show,
104
-                cshow['seriesname'],
105
-                cshow['language'],
106
-                str(cshow['id']),
107
-                cshow['lid'],
108
-                extra
109
-            )
110
-            if IS_PY2:
111
-                print(output.encode("UTF-8", "ignore"))
112
-            else:
113
-                print(output)
114
-
115
-    def selectSeries(self, allSeries):
116
-        self._displaySeries(allSeries)
117
-
118
-        if len(allSeries) == 1:
119
-            # Single result, return it!
120
-            print("Automatically selecting only result")
121
-            return allSeries[0]
122
-
123
-        if self.config['select_first'] is True:
124
-            print("Automatically returning first search result")
125
-            return allSeries[0]
126
-
127
-        while True: # return breaks this loop
128
-            try:
129
-                print("Enter choice (first number, return for default, 'all', ? for help):")
130
-                ans = user_input()
131
-            except KeyboardInterrupt:
132
-                raise tvdb_userabort("User aborted (^c keyboard interupt)")
133
-            except EOFError:
134
-                raise tvdb_userabort("User aborted (EOF received)")
135
-
136
-            log().debug('Got choice of: %s' % (ans))
137
-            try:
138
-                selected_id = int(ans) - 1 # The human entered 1 as first result, not zero
139
-            except ValueError: # Input was not number
140
-                if len(ans.strip()) == 0:
141
-                    # Default option
142
-                    log().debug('Default option, returning first series')
143
-                    return allSeries[0]
144
-                if ans == "q":
145
-                    log().debug('Got quit command (q)')
146
-                    raise tvdb_userabort("User aborted ('q' quit command)")
147
-                elif ans == "?":
148
-                    print("## Help")
149
-                    print("# Enter the number that corresponds to the correct show.")
150
-                    print("# a - display all results")
151
-                    print("# all - display all results")
152
-                    print("# ? - this help")
153
-                    print("# q - abort tvnamer")
154
-                    print("# Press return with no input to select first result")
155
-                elif ans.lower() in ["a", "all"]:
156
-                    self._displaySeries(allSeries, limit = None)
157
-                else:
158
-                    log().debug('Unknown keypress %s' % (ans))
159
-            else:
160
-                log().debug('Trying to return ID: %d' % (selected_id))
161
-                try:
162
-                    return allSeries[selected_id]
163
-                except IndexError:
164
-                    log().debug('Invalid show number entered!')
165
-                    print("Invalid number (%s) selected!")
166
-                    self._displaySeries(allSeries)
167
-
168
+from tvdb_api import BaseUI, ConsoleUI
169