From 05410e2aa0061f4bf623cd127530cbaac3e8e152 Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 14 Mar 2014 10:15:02 -0700 Subject: [PATCH] Switched TVDB/TVRage CacheHandlers to CacheControl. Replaced urllib2 with requests for both TVDB and TVRage. Updated cache cleanup code to process both TVDB and TVRage cache folders. --- lib/cachecontrol/__init__.py | 13 + lib/cachecontrol/adapter.py | 70 ++++ lib/cachecontrol/cache.py | 36 ++ lib/cachecontrol/caches/__init__.py | 18 + lib/cachecontrol/caches/file_cache.py | 43 +++ lib/cachecontrol/caches/redis_cache.py | 46 +++ lib/cachecontrol/compat.py | 12 + lib/cachecontrol/controller.py | 247 ++++++++++++++ lib/cachecontrol/patch_requests.py | 56 ++++ lib/cachecontrol/wrapper.py | 10 + lib/dateutil/zoneinfo/zoneinfo-2013i.tar.gz | Bin 168660 -> 0 bytes lib/lockfile/__init__.py | 317 ++++++++++++++++++ lib/lockfile/linklockfile.py | 73 ++++ lib/lockfile/mkdirlockfile.py | 83 +++++ lib/lockfile/pidlockfile.py | 193 +++++++++++ lib/lockfile/sqlitelockfile.py | 155 +++++++++ lib/lockfile/symlinklockfile.py | 69 ++++ lib/requests/__init__.py | 4 +- lib/requests/adapters.py | 13 +- lib/requests/api.py | 2 +- lib/requests/auth.py | 3 - lib/requests/certs.py | 2 +- lib/requests/exceptions.py | 17 +- lib/requests/models.py | 44 ++- lib/requests/packages/chardet/chardetect.py | 2 +- lib/requests/packages/urllib3/connection.py | 82 ++++- .../packages/urllib3/connectionpool.py | 34 +- .../packages/urllib3/contrib/pyopenssl.py | 48 ++- lib/requests/packages/urllib3/filepost.py | 11 +- lib/requests/packages/urllib3/poolmanager.py | 4 +- lib/requests/packages/urllib3/util.py | 5 + lib/requests/sessions.py | 60 ++-- lib/requests/utils.py | 2 +- lib/tvdb_api/tvdb_api.py | 119 ++----- lib/tvrage_api/tvrage_api.py | 146 +++----- sickbeard/indexers/generic.py | 19 +- sickbeard/indexers/indexer_api.py | 12 +- sickbeard/indexers/indexer_config.py | 29 -- sickbeard/indexers/test/test.py | 31 +- sickbeard/metadata/xbmc_12plus.py | 2 +- sickbeard/showUpdater.py | 42 +-- sickbeard/show_queue.py | 2 +- 42 files changed, 1817 insertions(+), 359 deletions(-) create mode 100644 lib/cachecontrol/__init__.py create mode 100644 lib/cachecontrol/adapter.py create mode 100644 lib/cachecontrol/cache.py create mode 100644 lib/cachecontrol/caches/__init__.py create mode 100644 lib/cachecontrol/caches/file_cache.py create mode 100644 lib/cachecontrol/caches/redis_cache.py create mode 100644 lib/cachecontrol/compat.py create mode 100644 lib/cachecontrol/controller.py create mode 100644 lib/cachecontrol/patch_requests.py create mode 100644 lib/cachecontrol/wrapper.py delete mode 100644 lib/dateutil/zoneinfo/zoneinfo-2013i.tar.gz create mode 100644 lib/lockfile/__init__.py create mode 100644 lib/lockfile/linklockfile.py create mode 100644 lib/lockfile/mkdirlockfile.py create mode 100644 lib/lockfile/pidlockfile.py create mode 100644 lib/lockfile/sqlitelockfile.py create mode 100644 lib/lockfile/symlinklockfile.py delete mode 100644 sickbeard/indexers/indexer_config.py diff --git a/lib/cachecontrol/__init__.py b/lib/cachecontrol/__init__.py new file mode 100644 index 00000000..693e11f1 --- /dev/null +++ b/lib/cachecontrol/__init__.py @@ -0,0 +1,13 @@ +"""CacheControl import Interface. + +Make it easy to import from cachecontrol without long namespaces. +""" + +# patch our requests.models.Response to make them pickleable in older +# versions of requests. + +import cachecontrol.patch_requests + +from cachecontrol.wrapper import CacheControl +from cachecontrol.adapter import CacheControlAdapter +from cachecontrol.controller import CacheController diff --git a/lib/cachecontrol/adapter.py b/lib/cachecontrol/adapter.py new file mode 100644 index 00000000..27f58fc7 --- /dev/null +++ b/lib/cachecontrol/adapter.py @@ -0,0 +1,70 @@ +from requests.adapters import HTTPAdapter + +from cachecontrol.controller import CacheController +from cachecontrol.cache import DictCache + + +class CacheControlAdapter(HTTPAdapter): + invalidating_methods = set(['PUT', 'DELETE']) + + def __init__(self, cache=None, cache_etags=True, *args, **kw): + super(CacheControlAdapter, self).__init__(*args, **kw) + self.cache = cache or DictCache() + self.controller = CacheController(self.cache, cache_etags=cache_etags) + + def send(self, request, **kw): + """Send a request. Use the request information to see if it + exists in the cache. + """ + if request.method == 'GET': + cached_response = self.controller.cached_request( + request.url, request.headers + ) + if cached_response: + # Cached responses should not have a raw field since + # they *cannot* be created from some stream. + cached_response.raw = None + return cached_response + + # check for etags and add headers if appropriate + headers = self.controller.add_headers(request.url) + request.headers.update(headers) + + resp = super(CacheControlAdapter, self).send(request, **kw) + return resp + + def build_response(self, request, response): + """Build a response by making a request or using the cache. + + This will end up calling send and returning a potentially + cached response + """ + resp = super(CacheControlAdapter, self).build_response( + request, response + ) + + # See if we should invalidate the cache. + if request.method in self.invalidating_methods and resp.ok: + cache_url = self.controller.cache_url(request.url) + self.cache.delete(cache_url) + + # Try to store the response if it is a GET + elif request.method == 'GET': + if response.status == 304: + # We must have sent an ETag request. This could mean + # that we've been expired already or that we simply + # have an etag. In either case, we want to try and + # update the cache if that is the case. + resp = self.controller.update_cached_response( + request, response + ) + else: + # try to cache the response + self.controller.cache_response(request, resp) + + # Give the request a from_cache attr to let people use it + # rather than testing for hasattr. + if not hasattr(resp, 'from_cache'): + resp.from_cache = False + + return resp diff --git a/lib/cachecontrol/cache.py b/lib/cachecontrol/cache.py new file mode 100644 index 00000000..feb7d3ed --- /dev/null +++ b/lib/cachecontrol/cache.py @@ -0,0 +1,36 @@ +""" +The cache object API for implementing caches. The default is just a +dictionary, which in turns means it is not threadsafe for writing. +""" +from threading import Lock + + +class BaseCache(object): + + def get(self, key): + raise NotImplemented() + + def set(self, key, value): + raise NotImplemented() + + def delete(self, key): + raise NotImplemented() + + +class DictCache(BaseCache): + + def __init__(self, init_dict=None): + self.lock = Lock() + self.data = init_dict or {} + + def get(self, key): + return self.data.get(key, None) + + def set(self, key, value): + with self.lock: + self.data.update({key: value}) + + def delete(self, key): + with self.lock: + if key in self.data: + self.data.pop(key) diff --git a/lib/cachecontrol/caches/__init__.py b/lib/cachecontrol/caches/__init__.py new file mode 100644 index 00000000..5e851b03 --- /dev/null +++ b/lib/cachecontrol/caches/__init__.py @@ -0,0 +1,18 @@ +from textwrap import dedent + +try: + from cachecontrol.caches.file_cache import FileCache +except ImportError: + notice = dedent(''' + NOTE: In order to use the FileCache you must have + lockfile installed. You can install it via pip: + pip install lockfile + ''') + print(notice) + + +try: + import redis + from cachecontrol.caches.redis_cache import RedisCache +except ImportError: + pass diff --git a/lib/cachecontrol/caches/file_cache.py b/lib/cachecontrol/caches/file_cache.py new file mode 100644 index 00000000..3a7d1a4c --- /dev/null +++ b/lib/cachecontrol/caches/file_cache.py @@ -0,0 +1,43 @@ +import os +import codecs + +from hashlib import md5 + +try: + from pickle import load, dump +except ImportError: + from cPickle import load, dump + +from lib.lockfile import FileLock + + +class FileCache(object): + + def __init__(self, directory, forever=False): + self.directory = directory + self.forever = forever + + if not os.path.isdir(self.directory): + os.mkdir(self.directory) + + def encode(self, x): + return md5(x.encode()).hexdigest() + + def _fn(self, name): + return os.path.join(self.directory, self.encode(name)) + + def get(self, key): + name = self._fn(key) + if os.path.exists(name): + return load(codecs.open(name, 'rb')) + + def set(self, key, value): + name = self._fn(key) + lock = FileLock(name) + with lock: + with codecs.open(lock.path, 'w+b') as fh: + dump(value, fh) + + def delete(self, key): + if not self.forever: + os.remove(self._fn(key)) diff --git a/lib/cachecontrol/caches/redis_cache.py b/lib/cachecontrol/caches/redis_cache.py new file mode 100644 index 00000000..d3814ebc --- /dev/null +++ b/lib/cachecontrol/caches/redis_cache.py @@ -0,0 +1,46 @@ +from __future__ import division + +from datetime import datetime + +try: + from cPickle import loads, dumps +except ImportError: # Python 3.x + from pickle import loads, dumps + + +def total_seconds(td): + """Python 2.6 compatability""" + if hasattr(td, 'total_seconds'): + return td.total_seconds() + + ms = td.microseconds + secs = (td.seconds + td.days * 24 * 3600) + return (ms + secs * 10**6) / 10**6 + + +class RedisCache(object): + + def __init__(self, conn): + self.conn = conn + + def get(self, key): + val = self.conn.get(key) + if val: + return loads(val) + return None + + def set(self, key, value, expires=None): + if not expires: + self.conn.set(key, dumps(value)) + else: + expires = expires - datetime.now() + self.conn.setex(key, total_seconds(expires), value) + + def delete(self, key): + self.conn.delete(key) + + def clear(self): + """Helper for clearing all the keys in a database. Use with + caution!""" + for key in self.conn.keys(): + self.conn.delete(key) diff --git a/lib/cachecontrol/compat.py b/lib/cachecontrol/compat.py new file mode 100644 index 00000000..1b6e596e --- /dev/null +++ b/lib/cachecontrol/compat.py @@ -0,0 +1,12 @@ +try: + from urllib.parse import urljoin +except ImportError: + from urlparse import urljoin + + +try: + import email.utils + parsedate_tz = email.utils.parsedate_tz +except ImportError: + import email.Utils + parsedate_tz = email.Utils.parsedate_tz diff --git a/lib/cachecontrol/controller.py b/lib/cachecontrol/controller.py new file mode 100644 index 00000000..67dd840e --- /dev/null +++ b/lib/cachecontrol/controller.py @@ -0,0 +1,247 @@ +""" +The httplib2 algorithms ported for use with requests. +""" +import re +import calendar +import time + +from cachecontrol.cache import DictCache +from cachecontrol.compat import parsedate_tz + + +URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?") + + +def parse_uri(uri): + """Parses a URI using the regex given in Appendix B of RFC 3986. + + (scheme, authority, path, query, fragment) = parse_uri(uri) + """ + groups = URI.match(uri).groups() + return (groups[1], groups[3], groups[4], groups[6], groups[8]) + + +class CacheController(object): + """An interface to see if request should cached or not. + """ + def __init__(self, cache=None, cache_etags=True): + self.cache = cache or DictCache() + self.cache_etags = cache_etags + + def _urlnorm(self, uri): + """Normalize the URL to create a safe key for the cache""" + (scheme, authority, path, query, fragment) = parse_uri(uri) + if not scheme or not authority: + raise Exception("Only absolute URIs are allowed. uri = %s" % uri) + authority = authority.lower() + scheme = scheme.lower() + if not path: + path = "/" + + # Could do syntax based normalization of the URI before + # computing the digest. See Section 6.2.2 of Std 66. + request_uri = query and "?".join([path, query]) or path + scheme = scheme.lower() + defrag_uri = scheme + "://" + authority + request_uri + + return defrag_uri + + def cache_url(self, uri): + return self._urlnorm(uri) + + def parse_cache_control(self, headers): + """ + Parse the cache control headers returning a dictionary with values + for the different directives. + """ + retval = {} + + cc_header = 'cache-control' + if 'Cache-Control' in headers: + cc_header = 'Cache-Control' + + if cc_header in headers: + parts = headers[cc_header].split(',') + parts_with_args = [ + tuple([x.strip().lower() for x in part.split("=", 1)]) + for part in parts if -1 != part.find("=")] + parts_wo_args = [(name.strip().lower(), 1) + for name in parts if -1 == name.find("=")] + retval = dict(parts_with_args + parts_wo_args) + return retval + + def cached_request(self, url, headers): + cache_url = self.cache_url(url) + cc = self.parse_cache_control(headers) + + # non-caching states + no_cache = True if 'no-cache' in cc else False + if 'max-age' in cc and cc['max-age'] == 0: + no_cache = True + + # see if it is in the cache anyways + in_cache = self.cache.get(cache_url) + if no_cache or not in_cache: + return False + + # It is in the cache, so lets see if it is going to be + # fresh enough + resp = self.cache.get(cache_url) + + # Check our Vary header to make sure our request headers match + # up. We don't delete it from the though, we just don't return + # our cached value. + # + # NOTE: Because httplib2 stores raw content, it denotes + # headers that were sent in the original response by + # adding -varied-$name. We don't have to do that b/c we + # are storing the object which has a reference to the + # original request. If that changes, then I'd propose + # using the varied headers in the cache key to avoid the + # situation all together. + if 'vary' in resp.headers: + varied_headers = resp.headers['vary'].replace(' ', '').split(',') + original_headers = resp.request.headers + for header in varied_headers: + # If our headers don't match for the headers listed in + # the vary header, then don't use the cached response + if headers.get(header, None) != original_headers.get(header): + return False + + now = time.time() + date = calendar.timegm( + parsedate_tz(resp.headers['date']) + ) + current_age = max(0, now - date) + + # TODO: There is an assumption that the result will be a + # requests response object. This may not be best since we + # could probably avoid instantiating or constructing the + # response until we know we need it. + resp_cc = self.parse_cache_control(resp.headers) + + # determine freshness + freshness_lifetime = 0 + if 'max-age' in resp_cc and resp_cc['max-age'].isdigit(): + freshness_lifetime = int(resp_cc['max-age']) + elif 'expires' in resp.headers: + expires = parsedate_tz(resp.headers['expires']) + if expires is not None: + expire_time = calendar.timegm(expires) - date + freshness_lifetime = max(0, expire_time) + + # determine if we are setting freshness limit in the req + if 'max-age' in cc: + try: + freshness_lifetime = int(cc['max-age']) + except ValueError: + freshness_lifetime = 0 + + if 'min-fresh' in cc: + try: + min_fresh = int(cc['min-fresh']) + except ValueError: + min_fresh = 0 + # adjust our current age by our min fresh + current_age += min_fresh + + # see how fresh we actually are + fresh = (freshness_lifetime > current_age) + + if fresh: + # make sure we set the from_cache to true + resp.from_cache = True + return resp + + # we're not fresh. If we don't have an Etag, clear it out + if 'etag' not in resp.headers: + self.cache.delete(cache_url) + + if 'etag' in resp.headers: + headers['If-None-Match'] = resp.headers['ETag'] + + if 'last-modified' in resp.headers: + headers['If-Modified-Since'] = resp.headers['Last-Modified'] + + # return the original handler + return False + + def add_headers(self, url): + resp = self.cache.get(url) + if resp and 'etag' in resp.headers: + return {'If-None-Match': resp.headers['etag']} + return {} + + def cache_response(self, request, resp): + """ + Algorithm for caching requests. + + This assumes a requests Response object. + """ + # From httplib2: Don't cache 206's since we aren't going to + # handle byte range requests + if resp.status_code not in [200, 203]: + return + + cc_req = self.parse_cache_control(request.headers) + cc = self.parse_cache_control(resp.headers) + + cache_url = self.cache_url(request.url) + + # Delete it from the cache if we happen to have it stored there + no_store = cc.get('no-store') or cc_req.get('no-store') + if no_store and self.cache.get(cache_url): + self.cache.delete(cache_url) + + # If we've been given an etag, then keep the response + if self.cache_etags and 'etag' in resp.headers: + self.cache.set(cache_url, resp) + + # Add to the cache if the response headers demand it. If there + # is no date header then we can't do anything about expiring + # the cache. + elif 'date' in resp.headers: + # cache when there is a max-age > 0 + if cc and cc.get('max-age'): + if int(cc['max-age']) > 0: + self.cache.set(cache_url, resp) + + # If the request can expire, it means we should cache it + # in the meantime. + elif 'expires' in resp.headers: + if resp.headers['expires']: + self.cache.set(cache_url, resp) + + def update_cached_response(self, request, response): + """On a 304 we will get a new set of headers that we want to + update our cached value with, assuming we have one. + + This should only ever be called when we've sent an ETag and + gotten a 304 as the response. + """ + cache_url = self.cache_url(request.url) + + resp = self.cache.get(cache_url) + + if not resp: + # we didn't have a cached response + return response + + # did so lets update our headers + resp.headers.update(resp.headers) + + # we want a 200 b/c we have content via the cache + request.status_code = 200 + + # update the request as it has the if-none-match header + any + # other headers that the server might have updated (ie Date, + # Cache-Control, Expires, etc.) + resp.request = request + + # update our cache + self.cache.set(cache_url, resp) + + # Let everyone know this was from the cache. + resp.from_cache = True + + return resp diff --git a/lib/cachecontrol/patch_requests.py b/lib/cachecontrol/patch_requests.py new file mode 100644 index 00000000..cad60e17 --- /dev/null +++ b/lib/cachecontrol/patch_requests.py @@ -0,0 +1,56 @@ +import requests + +from requests import models +from requests.packages.urllib3.response import HTTPResponse + +__attrs__ = [ + '_content', + 'status_code', + 'headers', + 'url', + 'history', + 'encoding', + 'reason', + 'cookies', + 'elapsed', +] + + +def response_getstate(self): + # consume everything + if not self._content_consumed: + self.content + + state = dict( + (attr, getattr(self, attr, None)) + for attr in __attrs__ + ) + + # deal with our raw content b/c we need it for our cookie jar + state['raw_original_response'] = self.raw._original_response + return state + + +def response_setstate(self, state): + for name, value in state.items(): + if name != 'raw_original_response': + setattr(self, name, value) + + setattr(self, 'raw', HTTPResponse()) + self.raw._original_response = state['raw_original_response'] + + +def make_responses_pickleable(): + try: + version_parts = [int(part) for part in requests.__version__.split('.')] + + # must be >= 2.2.x + if not version_parts[0] >= 2 or not version_parts[1] >= 2: + models.Response.__getstate__ = response_getstate + models.Response.__setstate__ = response_setstate + except: + raise + pass + + +make_responses_pickleable() diff --git a/lib/cachecontrol/wrapper.py b/lib/cachecontrol/wrapper.py new file mode 100644 index 00000000..d32f60a6 --- /dev/null +++ b/lib/cachecontrol/wrapper.py @@ -0,0 +1,10 @@ +from cachecontrol.adapter import CacheControlAdapter +from cachecontrol.cache import DictCache + + +def CacheControl(sess, cache=None, cache_etags=True): + cache = cache or DictCache() + adapter = CacheControlAdapter(cache, cache_etags=cache_etags) + sess.mount('http://', adapter) + + return sess diff --git a/lib/dateutil/zoneinfo/zoneinfo-2013i.tar.gz b/lib/dateutil/zoneinfo/zoneinfo-2013i.tar.gz deleted file mode 100644 index 2e30670c7cd4362d7a726d3132cc7f70fb643310..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168660 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

FFj7L^nrgLkcKJN+XKW4BbeBw9<`I(u067bazRY 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 lock = LockFile('somefile') +>>> try: +... lock.acquire() +... except AlreadyLocked: +... print 'somefile', 'is locked already.' +... except LockFailed: +... print 'somefile', 'can\\'t be locked.' +... else: +... print 'got lock' +got lock +>>> print lock.is_locked() +True +>>> lock.release() + +>>> lock = LockFile('somefile') +>>> print lock.is_locked() +False +>>> with lock: +... print lock.is_locked() +True +>>> print lock.is_locked() +False + +>>> lock = LockFile('somefile') +>>> # It is okay to lock twice from the same thread... +>>> with lock: +... lock.acquire() +... +>>> # Though no counter is kept, so you can't unlock multiple times... +>>> print lock.is_locked() +False + +Exceptions: + + Error - base class for other exceptions + LockError - base class for all locking exceptions + AlreadyLocked - Another thread or process already holds the lock + LockFailed - Lock failed for some other reason + UnlockError - base class for all unlocking exceptions + AlreadyUnlocked - File was not locked. + NotMyLock - File was locked but not by the current thread/process +""" + +from __future__ import absolute_import + +import sys +import socket +import os +import threading +import time +import urllib +import warnings +import functools + +# Work with PEP8 and non-PEP8 versions of threading module. +if not hasattr(threading, "current_thread"): + threading.current_thread = threading.currentThread +if not hasattr(threading.Thread, "get_name"): + threading.Thread.get_name = threading.Thread.getName + +__all__ = ['Error', 'LockError', 'LockTimeout', 'AlreadyLocked', + 'LockFailed', 'UnlockError', 'NotLocked', 'NotMyLock', + 'LinkLockFile', 'MkdirLockFile', 'SQLiteLockFile', + 'LockBase', 'locked'] + +class Error(Exception): + """ + Base class for other exceptions. + + >>> try: + ... raise Error + ... except Exception: + ... pass + """ + pass + +class LockError(Error): + """ + Base class for error arising from attempts to acquire the lock. + + >>> try: + ... raise LockError + ... except Error: + ... pass + """ + pass + +class LockTimeout(LockError): + """Raised when lock creation fails within a user-defined period of time. + + >>> try: + ... raise LockTimeout + ... except LockError: + ... pass + """ + pass + +class AlreadyLocked(LockError): + """Some other thread/process is locking the file. + + >>> try: + ... raise AlreadyLocked + ... except LockError: + ... pass + """ + pass + +class LockFailed(LockError): + """Lock file creation failed for some other reason. + + >>> try: + ... raise LockFailed + ... except LockError: + ... pass + """ + pass + +class UnlockError(Error): + """ + Base class for errors arising from attempts to release the lock. + + >>> try: + ... raise UnlockError + ... except Error: + ... pass + """ + pass + +class NotLocked(UnlockError): + """Raised when an attempt is made to unlock an unlocked file. + + >>> try: + ... raise NotLocked + ... except UnlockError: + ... pass + """ + pass + +class NotMyLock(UnlockError): + """Raised when an attempt is made to unlock a file someone else locked. + + >>> try: + ... raise NotMyLock + ... except UnlockError: + ... pass + """ + pass + +class LockBase: + """Base class for platform-specific lock classes.""" + def __init__(self, path, threaded=True, timeout=None): + """ + >>> lock = LockBase('somefile') + >>> lock = LockBase('somefile', threaded=False) + """ + self.path = path + self.lock_file = os.path.abspath(path) + ".lock" + self.hostname = socket.gethostname() + self.pid = os.getpid() + if threaded: + t = threading.current_thread() + # Thread objects in Python 2.4 and earlier do not have ident + # attrs. Worm around that. + ident = getattr(t, "ident", hash(t)) + self.tname = "-%x" % (ident & 0xffffffff) + else: + self.tname = "" + dirname = os.path.dirname(self.lock_file) + self.unique_name = os.path.join(dirname, + "%s%s.%s" % (self.hostname, + self.tname, + self.pid)) + self.timeout = timeout + + def acquire(self, timeout=None): + """ + Acquire the lock. + + * If timeout is omitted (or None), wait forever trying to lock the + file. + + * If timeout > 0, try to acquire the lock for that many seconds. If + the lock period expires and the file is still locked, raise + LockTimeout. + + * If timeout <= 0, raise AlreadyLocked immediately if the file is + already locked. + """ + raise NotImplemented("implement in subclass") + + def release(self): + """ + Release the lock. + + If the file is not locked, raise NotLocked. + """ + raise NotImplemented("implement in subclass") + + def is_locked(self): + """ + Tell whether or not the file is locked. + """ + raise NotImplemented("implement in subclass") + + def i_am_locking(self): + """ + Return True if this object is locking the file. + """ + raise NotImplemented("implement in subclass") + + def break_lock(self): + """ + Remove a lock. Useful if a locking thread failed to unlock. + """ + raise NotImplemented("implement in subclass") + + def __enter__(self): + """ + Context manager support. + """ + self.acquire() + return self + + def __exit__(self, *_exc): + """ + Context manager support. + """ + self.release() + + def __repr__(self): + return "<%s: %r -- %r>" % (self.__class__.__name__, self.unique_name, + self.path) + +def _fl_helper(cls, mod, *args, **kwds): + warnings.warn("Import from %s module instead of lockfile package" % mod, + DeprecationWarning, stacklevel=2) + # This is a bit funky, but it's only for awhile. The way the unit tests + # are constructed this function winds up as an unbound method, so it + # actually takes three args, not two. We want to toss out self. + if not isinstance(args[0], str): + # We are testing, avoid the first arg + args = args[1:] + if len(args) == 1 and not kwds: + kwds["threaded"] = True + return cls(*args, **kwds) + +def LinkFileLock(*args, **kwds): + """Factory function provided for backwards compatibility. + + Do not use in new code. Instead, import LinkLockFile from the + lockfile.linklockfile module. + """ + from . import linklockfile + return _fl_helper(linklockfile.LinkLockFile, "lockfile.linklockfile", + *args, **kwds) + +def MkdirFileLock(*args, **kwds): + """Factory function provided for backwards compatibility. + + Do not use in new code. Instead, import MkdirLockFile from the + lockfile.mkdirlockfile module. + """ + from . import mkdirlockfile + return _fl_helper(mkdirlockfile.MkdirLockFile, "lockfile.mkdirlockfile", + *args, **kwds) + +def SQLiteFileLock(*args, **kwds): + """Factory function provided for backwards compatibility. + + Do not use in new code. Instead, import SQLiteLockFile from the + lockfile.mkdirlockfile module. + """ + from . import sqlitelockfile + return _fl_helper(sqlitelockfile.SQLiteLockFile, "lockfile.sqlitelockfile", + *args, **kwds) + +def locked(path, timeout=None): + """Decorator which enables locks for decorated function. + + Arguments: + - path: path for lockfile. + - timeout (optional): Timeout for acquiring lock. + + Usage: + @locked('/var/run/myname', timeout=0) + def myname(...): + ... + """ + def decor(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + lock = FileLock(path, timeout=timeout) + lock.acquire() + try: + return func(*args, **kwargs) + finally: + lock.release() + return wrapper + return decor + +if hasattr(os, "link"): + from . import linklockfile as _llf + LockFile = _llf.LinkLockFile +else: + from . import mkdirlockfile as _mlf + LockFile = _mlf.MkdirLockFile + +FileLock = LockFile + diff --git a/lib/lockfile/linklockfile.py b/lib/lockfile/linklockfile.py new file mode 100644 index 00000000..9c506734 --- /dev/null +++ b/lib/lockfile/linklockfile.py @@ -0,0 +1,73 @@ +from __future__ import absolute_import + +import time +import os + +from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + +class LinkLockFile(LockBase): + """Lock access to a file using atomic property of link(2). + + >>> lock = LinkLockFile('somefile') + >>> lock = LinkLockFile('somefile', threaded=False) + """ + + def acquire(self, timeout=None): + try: + open(self.unique_name, "wb").close() + except IOError: + raise LockFailed("failed to create %s" % self.unique_name) + + timeout = timeout is not None and timeout or self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + # Try and create a hard link to it. + try: + os.link(self.unique_name, self.lock_file) + except OSError: + # Link creation failed. Maybe we've double-locked? + nlinks = os.stat(self.unique_name).st_nlink + if nlinks == 2: + # The original link plus the one I created == 2. We're + # good to go. + return + else: + # Otherwise the lock creation failed. + if timeout is not None and time.time() > end_time: + os.unlink(self.unique_name) + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(timeout is not None and timeout/10 or 0.1) + else: + # Link creation succeeded. We're good to go. + return + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + elif not os.path.exists(self.unique_name): + raise NotMyLock("%s is locked, but not by me" % self.path) + os.unlink(self.unique_name) + os.unlink(self.lock_file) + + def is_locked(self): + return os.path.exists(self.lock_file) + + def i_am_locking(self): + return (self.is_locked() and + os.path.exists(self.unique_name) and + os.stat(self.unique_name).st_nlink == 2) + + def break_lock(self): + if os.path.exists(self.lock_file): + os.unlink(self.lock_file) + diff --git a/lib/lockfile/mkdirlockfile.py b/lib/lockfile/mkdirlockfile.py new file mode 100644 index 00000000..8d2c801f --- /dev/null +++ b/lib/lockfile/mkdirlockfile.py @@ -0,0 +1,83 @@ +from __future__ import absolute_import, division + +import time +import os +import sys +import errno + +from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + +class MkdirLockFile(LockBase): + """Lock file by creating a directory.""" + def __init__(self, path, threaded=True, timeout=None): + """ + >>> lock = MkdirLockFile('somefile') + >>> lock = MkdirLockFile('somefile', threaded=False) + """ + LockBase.__init__(self, path, threaded, timeout) + # Lock file itself is a directory. Place the unique file name into + # it. + self.unique_name = os.path.join(self.lock_file, + "%s.%s%s" % (self.hostname, + self.tname, + self.pid)) + + def acquire(self, timeout=None): + timeout = timeout is not None and timeout or self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + if timeout is None: + wait = 0.1 + else: + wait = max(0, timeout / 10) + + while True: + try: + os.mkdir(self.lock_file) + except OSError: + err = sys.exc_info()[1] + if err.errno == errno.EEXIST: + # Already locked. + if os.path.exists(self.unique_name): + # Already locked by me. + return + if timeout is not None and time.time() > end_time: + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + # Someone else has the lock. + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(wait) + else: + # Couldn't create the lock for some other reason + raise LockFailed("failed to create %s" % self.lock_file) + else: + open(self.unique_name, "wb").close() + return + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + elif not os.path.exists(self.unique_name): + raise NotMyLock("%s is locked, but not by me" % self.path) + os.unlink(self.unique_name) + os.rmdir(self.lock_file) + + def is_locked(self): + return os.path.exists(self.lock_file) + + def i_am_locking(self): + return (self.is_locked() and + os.path.exists(self.unique_name)) + + def break_lock(self): + if os.path.exists(self.lock_file): + for name in os.listdir(self.lock_file): + os.unlink(os.path.join(self.lock_file, name)) + os.rmdir(self.lock_file) diff --git a/lib/lockfile/pidlockfile.py b/lib/lockfile/pidlockfile.py new file mode 100644 index 00000000..e92f9ead --- /dev/null +++ b/lib/lockfile/pidlockfile.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- + +# pidlockfile.py +# +# Copyright © 2008–2009 Ben Finney +# +# This is free software: you may copy, modify, and/or distribute this work +# under the terms of the Python Software Foundation License, version 2 or +# later as published by the Python Software Foundation. +# No warranty expressed or implied. See the file LICENSE.PSF-2 for details. + +""" Lockfile behaviour implemented via Unix PID files. + """ + +from __future__ import absolute_import + +import os +import sys +import errno +import time + +from . import (LockBase, AlreadyLocked, LockFailed, NotLocked, NotMyLock, + LockTimeout) + + +class PIDLockFile(LockBase): + """ Lockfile implemented as a Unix PID file. + + The lock file is a normal file named by the attribute `path`. + A lock's PID file contains a single line of text, containing + the process ID (PID) of the process that acquired the lock. + + >>> lock = PIDLockFile('somefile') + >>> lock = PIDLockFile('somefile') + """ + + def __init__(self, path, threaded=False, timeout=None): + # pid lockfiles don't support threaded operation, so always force + # False as the threaded arg. + LockBase.__init__(self, path, False, timeout) + dirname = os.path.dirname(self.lock_file) + basename = os.path.split(self.path)[-1] + self.unique_name = self.path + + def read_pid(self): + """ Get the PID from the lock file. + """ + return read_pid_from_pidfile(self.path) + + def is_locked(self): + """ Test if the lock is currently held. + + The lock is held if the PID file for this lock exists. + + """ + return os.path.exists(self.path) + + def i_am_locking(self): + """ Test if the lock is held by the current process. + + Returns ``True`` if the current process ID matches the + number stored in the PID file. + """ + return self.is_locked() and os.getpid() == self.read_pid() + + def acquire(self, timeout=None): + """ Acquire the lock. + + Creates the PID file for this lock, or raises an error if + the lock could not be acquired. + """ + + timeout = timeout is not None and timeout or self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + try: + write_pid_to_pidfile(self.path) + except OSError as exc: + if exc.errno == errno.EEXIST: + # The lock creation failed. Maybe sleep a bit. + if timeout is not None and time.time() > end_time: + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(timeout is not None and timeout/10 or 0.1) + else: + raise LockFailed("failed to create %s" % self.path) + else: + return + + def release(self): + """ Release the lock. + + Removes the PID file to release the lock, or raises an + error if the current process does not hold the lock. + + """ + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + if not self.i_am_locking(): + raise NotMyLock("%s is locked, but not by me" % self.path) + remove_existing_pidfile(self.path) + + def break_lock(self): + """ Break an existing lock. + + Removes the PID file if it already exists, otherwise does + nothing. + + """ + remove_existing_pidfile(self.path) + +def read_pid_from_pidfile(pidfile_path): + """ Read the PID recorded in the named PID file. + + Read and return the numeric PID recorded as text in the named + PID file. If the PID file cannot be read, or if the content is + not a valid PID, return ``None``. + + """ + pid = None + try: + pidfile = open(pidfile_path, 'r') + except IOError: + pass + else: + # According to the FHS 2.3 section on PID files in /var/run: + # + # The file must consist of the process identifier in + # ASCII-encoded decimal, followed by a newline character. + # + # Programs that read PID files should be somewhat flexible + # in what they accept; i.e., they should ignore extra + # whitespace, leading zeroes, absence of the trailing + # newline, or additional lines in the PID file. + + line = pidfile.readline().strip() + try: + pid = int(line) + except ValueError: + pass + pidfile.close() + + return pid + + +def write_pid_to_pidfile(pidfile_path): + """ Write the PID in the named PID file. + + Get the numeric process ID (“PID”) of the current process + and write it to the named file as a line of text. + + """ + open_flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY) + open_mode = 0o644 + pidfile_fd = os.open(pidfile_path, open_flags, open_mode) + pidfile = os.fdopen(pidfile_fd, 'w') + + # According to the FHS 2.3 section on PID files in /var/run: + # + # The file must consist of the process identifier in + # ASCII-encoded decimal, followed by a newline character. For + # example, if crond was process number 25, /var/run/crond.pid + # would contain three characters: two, five, and newline. + + pid = os.getpid() + line = "%(pid)d\n" % vars() + pidfile.write(line) + pidfile.close() + + +def remove_existing_pidfile(pidfile_path): + """ Remove the named PID file if it exists. + + Removing a PID file that doesn't already exist puts us in the + desired state, so we ignore the condition if the file does not + exist. + + """ + try: + os.remove(pidfile_path) + except OSError as exc: + if exc.errno == errno.ENOENT: + pass + else: + raise diff --git a/lib/lockfile/sqlitelockfile.py b/lib/lockfile/sqlitelockfile.py new file mode 100644 index 00000000..7dee4a85 --- /dev/null +++ b/lib/lockfile/sqlitelockfile.py @@ -0,0 +1,155 @@ +from __future__ import absolute_import, division + +import time +import os + +try: + unicode +except NameError: + unicode = str + +from . import LockBase, NotLocked, NotMyLock, LockTimeout, AlreadyLocked + +class SQLiteLockFile(LockBase): + "Demonstrate SQL-based locking." + + testdb = None + + def __init__(self, path, threaded=True, timeout=None): + """ + >>> lock = SQLiteLockFile('somefile') + >>> lock = SQLiteLockFile('somefile', threaded=False) + """ + LockBase.__init__(self, path, threaded, timeout) + self.lock_file = unicode(self.lock_file) + self.unique_name = unicode(self.unique_name) + + if SQLiteLockFile.testdb is None: + import tempfile + _fd, testdb = tempfile.mkstemp() + os.close(_fd) + os.unlink(testdb) + del _fd, tempfile + SQLiteLockFile.testdb = testdb + + import sqlite3 + self.connection = sqlite3.connect(SQLiteLockFile.testdb) + + c = self.connection.cursor() + try: + c.execute("create table locks" + "(" + " lock_file varchar(32)," + " unique_name varchar(32)" + ")") + except sqlite3.OperationalError: + pass + else: + self.connection.commit() + import atexit + atexit.register(os.unlink, SQLiteLockFile.testdb) + + def acquire(self, timeout=None): + timeout = timeout is not None and timeout or self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + if timeout is None: + wait = 0.1 + elif timeout <= 0: + wait = 0 + else: + wait = timeout / 10 + + cursor = self.connection.cursor() + + while True: + if not self.is_locked(): + # Not locked. Try to lock it. + cursor.execute("insert into locks" + " (lock_file, unique_name)" + " values" + " (?, ?)", + (self.lock_file, self.unique_name)) + self.connection.commit() + + # Check to see if we are the only lock holder. + cursor.execute("select * from locks" + " where unique_name = ?", + (self.unique_name,)) + rows = cursor.fetchall() + if len(rows) > 1: + # Nope. Someone else got there. Remove our lock. + cursor.execute("delete from locks" + " where unique_name = ?", + (self.unique_name,)) + self.connection.commit() + else: + # Yup. We're done, so go home. + return + else: + # Check to see if we are the only lock holder. + cursor.execute("select * from locks" + " where unique_name = ?", + (self.unique_name,)) + rows = cursor.fetchall() + if len(rows) == 1: + # We're the locker, so go home. + return + + # Maybe we should wait a bit longer. + if timeout is not None and time.time() > end_time: + if timeout > 0: + # No more waiting. + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + # Someone else has the lock and we are impatient.. + raise AlreadyLocked("%s is already locked" % self.path) + + # Well, okay. We'll give it a bit longer. + time.sleep(wait) + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + if not self.i_am_locking(): + raise NotMyLock("%s is locked, but not by me (by %s)" % + (self.unique_name, self._who_is_locking())) + cursor = self.connection.cursor() + cursor.execute("delete from locks" + " where unique_name = ?", + (self.unique_name,)) + self.connection.commit() + + def _who_is_locking(self): + cursor = self.connection.cursor() + cursor.execute("select unique_name from locks" + " where lock_file = ?", + (self.lock_file,)) + return cursor.fetchone()[0] + + def is_locked(self): + cursor = self.connection.cursor() + cursor.execute("select * from locks" + " where lock_file = ?", + (self.lock_file,)) + rows = cursor.fetchall() + return not not rows + + def i_am_locking(self): + cursor = self.connection.cursor() + cursor.execute("select * from locks" + " where lock_file = ?" + " and unique_name = ?", + (self.lock_file, self.unique_name)) + return not not cursor.fetchall() + + def break_lock(self): + cursor = self.connection.cursor() + cursor.execute("delete from locks" + " where lock_file = ?", + (self.lock_file,)) + self.connection.commit() diff --git a/lib/lockfile/symlinklockfile.py b/lib/lockfile/symlinklockfile.py new file mode 100644 index 00000000..57551a36 --- /dev/null +++ b/lib/lockfile/symlinklockfile.py @@ -0,0 +1,69 @@ +from __future__ import absolute_import + +import time +import os + +from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + +class SymlinkLockFile(LockBase): + """Lock access to a file using symlink(2).""" + + def __init__(self, path, threaded=True, timeout=None): + # super(SymlinkLockFile).__init(...) + LockBase.__init__(self, path, threaded, timeout) + # split it back! + self.unique_name = os.path.split(self.unique_name)[1] + + def acquire(self, timeout=None): + # Hopefully unnecessary for symlink. + #try: + # open(self.unique_name, "wb").close() + #except IOError: + # raise LockFailed("failed to create %s" % self.unique_name) + timeout = timeout is not None and timeout or self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + # Try and create a symbolic link to it. + try: + os.symlink(self.unique_name, self.lock_file) + except OSError: + # Link creation failed. Maybe we've double-locked? + if self.i_am_locking(): + # Linked to out unique name. Proceed. + return + else: + # Otherwise the lock creation failed. + if timeout is not None and time.time() > end_time: + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(timeout/10 if timeout is not None else 0.1) + else: + # Link creation succeeded. We're good to go. + return + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + elif not self.i_am_locking(): + raise NotMyLock("%s is locked, but not by me" % self.path) + os.unlink(self.lock_file) + + def is_locked(self): + return os.path.islink(self.lock_file) + + def i_am_locking(self): + return os.path.islink(self.lock_file) and \ + os.readlink(self.lock_file) == self.unique_name + + def break_lock(self): + if os.path.islink(self.lock_file): # exists && link + os.unlink(self.lock_file) diff --git a/lib/requests/__init__.py b/lib/requests/__init__.py index 90fcb033..bba19002 100644 --- a/lib/requests/__init__.py +++ b/lib/requests/__init__.py @@ -42,8 +42,8 @@ is at . """ __title__ = 'requests' -__version__ = '2.2.0' -__build__ = 0x020200 +__version__ = '2.3.0' +__build__ = 0x020300 __author__ = 'Kenneth Reitz' __license__ = 'Apache 2.0' __copyright__ = 'Copyright 2014 Kenneth Reitz' diff --git a/lib/requests/adapters.py b/lib/requests/adapters.py index dd10e959..28bea07c 100644 --- a/lib/requests/adapters.py +++ b/lib/requests/adapters.py @@ -310,10 +310,7 @@ class HTTPAdapter(BaseAdapter): chunked = not (request.body is None or 'Content-Length' in request.headers) - if stream: - timeout = TimeoutSauce(connect=timeout) - else: - timeout = TimeoutSauce(connect=timeout, read=timeout) + timeout = TimeoutSauce(connect=timeout, read=timeout) try: if not chunked: @@ -372,19 +369,19 @@ class HTTPAdapter(BaseAdapter): conn._put_conn(low_conn) except socket.error as sockerr: - raise ConnectionError(sockerr) + raise ConnectionError(sockerr, request=request) except MaxRetryError as e: - raise ConnectionError(e) + raise ConnectionError(e, request=request) except _ProxyError as e: raise ProxyError(e) except (_SSLError, _HTTPError) as e: if isinstance(e, _SSLError): - raise SSLError(e) + raise SSLError(e, request=request) elif isinstance(e, TimeoutError): - raise Timeout(e) + raise Timeout(e, request=request) else: raise diff --git a/lib/requests/api.py b/lib/requests/api.py index baf43dd6..01d853d5 100644 --- a/lib/requests/api.py +++ b/lib/requests/api.py @@ -26,7 +26,7 @@ def request(method, url, **kwargs): :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. :param files: (optional) Dictionary of 'name': file-like-objects (or {'name': ('filename', fileobj)}) for multipart encoding upload. :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. + :param timeout: (optional) Float describing the timeout of the request in seconds. :param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed. :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. :param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided. diff --git a/lib/requests/auth.py b/lib/requests/auth.py index 6664cd80..9f831b7a 100644 --- a/lib/requests/auth.py +++ b/lib/requests/auth.py @@ -11,7 +11,6 @@ import os import re import time import hashlib -import logging from base64 import b64encode @@ -19,8 +18,6 @@ from .compat import urlparse, str from .cookies import extract_cookies_to_jar from .utils import parse_dict_header -log = logging.getLogger(__name__) - CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded' CONTENT_TYPE_MULTI_PART = 'multipart/form-data' diff --git a/lib/requests/certs.py b/lib/requests/certs.py index 57229101..bc008261 100644 --- a/lib/requests/certs.py +++ b/lib/requests/certs.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # -*- coding: utf-8 -*- """ diff --git a/lib/requests/exceptions.py b/lib/requests/exceptions.py index cd3c7600..a4ee9d63 100644 --- a/lib/requests/exceptions.py +++ b/lib/requests/exceptions.py @@ -14,15 +14,22 @@ class RequestException(IOError): """There was an ambiguous exception that occurred while handling your request.""" + def __init__(self, *args, **kwargs): + """ + Initialize RequestException with `request` and `response` objects. + """ + response = kwargs.pop('response', None) + self.response = response + self.request = kwargs.pop('request', None) + if (response is not None and not self.request and + hasattr(response, 'request')): + self.request = self.response.request + super(RequestException, self).__init__(*args, **kwargs) + class HTTPError(RequestException): """An HTTP error occurred.""" - def __init__(self, *args, **kwargs): - """ Initializes HTTPError with optional `response` object. """ - self.response = kwargs.pop('response', None) - super(HTTPError, self).__init__(*args, **kwargs) - class ConnectionError(RequestException): """A Connection error occurred.""" diff --git a/lib/requests/models.py b/lib/requests/models.py index ae46a831..e2fa09f8 100644 --- a/lib/requests/models.py +++ b/lib/requests/models.py @@ -8,7 +8,6 @@ This module contains the primary objects that power Requests. """ import collections -import logging import datetime from io import BytesIO, UnsupportedOperation @@ -31,12 +30,20 @@ from .utils import ( from .compat import ( cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO, is_py2, chardet, json, builtin_str, basestring, IncompleteRead) +from .status_codes import codes +#: The set of HTTP status codes that indicate an automatically +#: processable redirect. +REDIRECT_STATI = ( + codes.moved, # 301 + codes.found, # 302 + codes.other, # 303 + codes.temporary_moved, # 307 +) +DEFAULT_REDIRECT_LIMIT = 30 CONTENT_CHUNK_SIZE = 10 * 1024 ITER_CHUNK_SIZE = 512 -log = logging.getLogger(__name__) - class RequestEncodingMixin(object): @property @@ -517,7 +524,7 @@ class Response(object): self._content = False self._content_consumed = False - #: Integer Code of responded HTTP Status. + #: Integer Code of responded HTTP Status, e.g. 404 or 200. self.status_code = None #: Case-insensitive Dictionary of Response Headers. @@ -541,6 +548,7 @@ class Response(object): #: up here. The list is sorted from the oldest to the most recent request. self.history = [] + #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK". self.reason = None #: A CookieJar of Cookies the server sent back. @@ -567,6 +575,7 @@ class Response(object): # pickled objects do not have .raw setattr(self, '_content_consumed', True) + setattr(self, 'raw', None) def __repr__(self): return '' % (self.status_code) @@ -591,10 +600,16 @@ class Response(object): return False return True + @property + def is_redirect(self): + """True if this Response is a well-formed HTTP redirect that could have + been processed automatically (by :meth:`Session.resolve_redirects`). + """ + return ('location' in self.headers and self.status_code in REDIRECT_STATI) + @property def apparent_encoding(self): - """The apparent encoding, provided by the lovely Charade library - (Thanks, Ian!).""" + """The apparent encoding, provided by the chardet library""" return chardet.detect(self.content)['encoding'] def iter_content(self, chunk_size=1, decode_unicode=False): @@ -612,8 +627,7 @@ class Response(object): try: # Special case for urllib3. try: - for chunk in self.raw.stream(chunk_size, - decode_content=True): + for chunk in self.raw.stream(chunk_size, decode_content=True): yield chunk except IncompleteRead as e: raise ChunkedEncodingError(e) @@ -644,8 +658,7 @@ class Response(object): pending = None - for chunk in self.iter_content(chunk_size=chunk_size, - decode_unicode=decode_unicode): + for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode): if pending is not None: chunk = pending + chunk @@ -693,7 +706,7 @@ class Response(object): If Response.encoding is None, encoding will be guessed using ``chardet``. - The encoding of the response content is determined based soley on HTTP + The encoding of the response content is determined based solely on HTTP headers, following RFC 2616 to the letter. If you can take advantage of non-HTTP knowledge to make a better guess at the encoding, you should set ``r.encoding`` appropriately before accessing this property. @@ -737,7 +750,14 @@ class Response(object): # a best guess). encoding = guess_json_utf(self.content) if encoding is not None: - return json.loads(self.content.decode(encoding), **kwargs) + try: + return json.loads(self.content.decode(encoding), **kwargs) + except UnicodeDecodeError: + # Wrong UTF codec detected; usually because it's not UTF-8 + # but some other 8-bit codec. This is an RFC violation, + # and the server didn't bother to tell us what codec *was* + # used. + pass return json.loads(self.text, **kwargs) @property diff --git a/lib/requests/packages/chardet/chardetect.py b/lib/requests/packages/chardet/chardetect.py index 31010659..ecd0163b 100644 --- a/lib/requests/packages/chardet/chardetect.py +++ b/lib/requests/packages/chardet/chardetect.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python """ Script which takes one or more file paths and reports on their detected encodings diff --git a/lib/requests/packages/urllib3/connection.py b/lib/requests/packages/urllib3/connection.py index c3f302d3..21247745 100644 --- a/lib/requests/packages/urllib3/connection.py +++ b/lib/requests/packages/urllib3/connection.py @@ -8,9 +8,9 @@ import socket from socket import timeout as SocketTimeout try: # Python 3 - from http.client import HTTPConnection, HTTPException + from http.client import HTTPConnection as _HTTPConnection, HTTPException except ImportError: - from httplib import HTTPConnection, HTTPException + from httplib import HTTPConnection as _HTTPConnection, HTTPException class DummyConnection(object): "Used to detect a failed ConnectionCls import." @@ -24,9 +24,9 @@ try: # Compiled with SSL? pass try: # Python 3 - from http.client import HTTPSConnection + from http.client import HTTPSConnection as _HTTPSConnection except ImportError: - from httplib import HTTPSConnection + from httplib import HTTPSConnection as _HTTPSConnection import ssl BaseSSLError = ssl.SSLError @@ -45,6 +45,69 @@ from .util import ( ssl_wrap_socket, ) + +port_by_scheme = { + 'http': 80, + 'https': 443, +} + + +class HTTPConnection(_HTTPConnection, object): + default_port = port_by_scheme['http'] + + # By default, disable Nagle's Algorithm. + tcp_nodelay = 1 + + def _new_conn(self): + """ Establish a socket connection and set nodelay settings on it + + :return: a new socket connection + """ + try: + conn = socket.create_connection( + (self.host, self.port), + self.timeout, + self.source_address, + ) + except AttributeError: # Python 2.6 + conn = socket.create_connection( + (self.host, self.port), + self.timeout, + ) + conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, + self.tcp_nodelay) + return conn + + def _prepare_conn(self, conn): + self.sock = conn + if self._tunnel_host: + # TODO: Fix tunnel so it doesn't depend on self.sock state. + self._tunnel() + + def connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + +class HTTPSConnection(HTTPConnection): + default_port = port_by_scheme['https'] + + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + source_address=None): + try: + HTTPConnection.__init__(self, host, port, strict, timeout, source_address) + except TypeError: # Python 2.6 + HTTPConnection.__init__(self, host, port, strict, timeout) + self.key_file = key_file + self.cert_file = cert_file + + def connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + self.sock = ssl.wrap_socket(conn, self.key_file, self.cert_file) + + class VerifiedHTTPSConnection(HTTPSConnection): """ Based on httplib.HTTPSConnection but wraps the socket with @@ -73,9 +136,12 @@ class VerifiedHTTPSConnection(HTTPSConnection): timeout=self.timeout, ) except SocketTimeout: - raise ConnectTimeoutError( - self, "Connection to %s timed out. (connect timeout=%s)" % - (self.host, self.timeout)) + raise ConnectTimeoutError( + self, "Connection to %s timed out. (connect timeout=%s)" % + (self.host, self.timeout)) + + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, + self.tcp_nodelay) resolved_cert_reqs = resolve_cert_reqs(self.cert_reqs) resolved_ssl_version = resolve_ssl_version(self.ssl_version) @@ -107,4 +173,6 @@ class VerifiedHTTPSConnection(HTTPSConnection): if ssl: + # Make a copy for testing. + UnverifiedHTTPSConnection = HTTPSConnection HTTPSConnection = VerifiedHTTPSConnection diff --git a/lib/requests/packages/urllib3/connectionpool.py b/lib/requests/packages/urllib3/connectionpool.py index 44ecffd0..243d700e 100644 --- a/lib/requests/packages/urllib3/connectionpool.py +++ b/lib/requests/packages/urllib3/connectionpool.py @@ -31,6 +31,7 @@ from .exceptions import ( from .packages.ssl_match_hostname import CertificateError from .packages import six from .connection import ( + port_by_scheme, DummyConnection, HTTPConnection, HTTPSConnection, VerifiedHTTPSConnection, HTTPException, BaseSSLError, @@ -51,12 +52,6 @@ log = logging.getLogger(__name__) _Default = object() -port_by_scheme = { - 'http': 80, - 'https': 443, -} - - ## Pool objects class ConnectionPool(object): @@ -169,7 +164,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): def _new_conn(self): """ - Return a fresh :class:`httplib.HTTPConnection`. + Return a fresh :class:`HTTPConnection`. """ self.num_connections += 1 log.info("Starting new HTTP connection (%d): %s" % @@ -179,9 +174,14 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): if not six.PY3: # Python 2 extra_params['strict'] = self.strict - return self.ConnectionCls(host=self.host, port=self.port, + conn = self.ConnectionCls(host=self.host, port=self.port, timeout=self.timeout.connect_timeout, **extra_params) + if self.proxy is not None: + # Enable Nagle's algorithm for proxies, to avoid packet + # fragmentation. + conn.tcp_nodelay = 0 + return conn def _get_conn(self, timeout=None): """ @@ -260,7 +260,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): def _make_request(self, conn, method, url, timeout=_Default, **httplib_request_kw): """ - Perform a request on a given httplib connection object taken from our + Perform a request on a given urllib connection object taken from our pool. :param conn: @@ -517,17 +517,17 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): raise except (HTTPException, SocketError) as e: - if isinstance(e, SocketError) and self.proxy is not None: - raise ProxyError('Cannot connect to proxy. ' - 'Socket error: %s.' % e) - # Connection broken, discard. It will be replaced next _get_conn(). conn = None # This is necessary so we can access e below err = e if retries == 0: - raise MaxRetryError(self, url, e) + if isinstance(e, SocketError) and self.proxy is not None: + raise ProxyError('Cannot connect to proxy. ' + 'Socket error: %s.' % e) + else: + raise MaxRetryError(self, url, e) finally: if release_conn: @@ -565,7 +565,7 @@ class HTTPSConnectionPool(HTTPConnectionPool): When Python is compiled with the :mod:`ssl` module, then :class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates, - instead of :class:`httplib.HTTPSConnection`. + instead of :class:`.HTTPSConnection`. :class:`.VerifiedHTTPSConnection` uses one of ``assert_fingerprint``, ``assert_hostname`` and ``host`` in this order to verify connections. @@ -652,6 +652,10 @@ class HTTPSConnectionPool(HTTPConnectionPool): conn = self.ConnectionCls(host=actual_host, port=actual_port, timeout=self.timeout.connect_timeout, **extra_params) + if self.proxy is not None: + # Enable Nagle's algorithm for proxies, to avoid packet + # fragmentation. + conn.tcp_nodelay = 0 return self._prepare_conn(conn) diff --git a/lib/requests/packages/urllib3/contrib/pyopenssl.py b/lib/requests/packages/urllib3/contrib/pyopenssl.py index f78e7170..d9bda15a 100644 --- a/lib/requests/packages/urllib3/contrib/pyopenssl.py +++ b/lib/requests/packages/urllib3/contrib/pyopenssl.py @@ -1,4 +1,4 @@ -'''SSL with SNI-support for Python 2. +'''SSL with SNI_-support for Python 2. This needs the following packages installed: @@ -18,12 +18,31 @@ your application begins using ``urllib3``, like this:: Now you can use :mod:`urllib3` as you normally would, and it will support SNI when the required modules are installed. + +Activating this module also has the positive side effect of disabling SSL/TLS +encryption in Python 2 (see `CRIME attack`_). + +If you want to configure the default list of supported cipher suites, you can +set the ``urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST`` variable. + +Module Variables +---------------- + +:var DEFAULT_SSL_CIPHER_LIST: The list of supported SSL/TLS cipher suites. + Default: ``EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 + EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EDH+aRSA EECDH RC4 !aNULL !eNULL !LOW !3DES + !MD5 !EXP !PSK !SRP !DSS'`` + +.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication +.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) + ''' from ndg.httpsclient.ssl_peer_verification import SUBJ_ALT_NAME_SUPPORT -from ndg.httpsclient.subj_alt_name import SubjectAltName +from ndg.httpsclient.subj_alt_name import SubjectAltName as BaseSubjectAltName import OpenSSL.SSL from pyasn1.codec.der import decoder as der_decoder +from pyasn1.type import univ, constraint from socket import _fileobject import ssl import select @@ -50,6 +69,13 @@ _openssl_verify = { + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, } +# Default SSL/TLS cipher list. +# Recommendation by https://community.qualys.com/blogs/securitylabs/2013/08/05/ +# configuring-apache-nginx-and-openssl-for-forward-secrecy +DEFAULT_SSL_CIPHER_LIST = 'EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM ' + \ + 'EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EDH+aRSA ' + \ + 'EECDH RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS' + orig_util_HAS_SNI = util.HAS_SNI orig_connection_ssl_wrap_socket = connection.ssl_wrap_socket @@ -69,6 +95,17 @@ def extract_from_urllib3(): util.HAS_SNI = orig_util_HAS_SNI +### Note: This is a slightly bug-fixed version of same from ndg-httpsclient. +class SubjectAltName(BaseSubjectAltName): + '''ASN.1 implementation for subjectAltNames support''' + + # There is no limit to how many SAN certificates a certificate may have, + # however this needs to have some limit so we'll set an arbitrarily high + # limit. + sizeSpec = univ.SequenceOf.sizeSpec + \ + constraint.ValueSizeConstraint(1, 1024) + + ### Note: This is a slightly bug-fixed version of same from ndg-httpsclient. def get_subj_alt_name(peer_cert): # Search through extensions @@ -330,6 +367,13 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None, except OpenSSL.SSL.Error as e: raise ssl.SSLError('bad ca_certs: %r' % ca_certs, e) + # Disable TLS compression to migitate CRIME attack (issue #309) + OP_NO_COMPRESSION = 0x20000 + ctx.set_options(OP_NO_COMPRESSION) + + # Set list of supported ciphersuites. + ctx.set_cipher_list(DEFAULT_SSL_CIPHER_LIST) + cnx = OpenSSL.SSL.Connection(ctx, sock) cnx.set_tlsext_host_name(server_hostname) cnx.set_connect_state() diff --git a/lib/requests/packages/urllib3/filepost.py b/lib/requests/packages/urllib3/filepost.py index 4575582e..e8b30bdd 100644 --- a/lib/requests/packages/urllib3/filepost.py +++ b/lib/requests/packages/urllib3/filepost.py @@ -46,16 +46,15 @@ def iter_field_objects(fields): def iter_fields(fields): """ + .. deprecated:: 1.6 + Iterate over fields. - .. deprecated :: - - The addition of `~urllib3.fields.RequestField` makes this function - obsolete. Instead, use :func:`iter_field_objects`, which returns - `~urllib3.fields.RequestField` objects, instead. + The addition of :class:`~urllib3.fields.RequestField` makes this function + obsolete. Instead, use :func:`iter_field_objects`, which returns + :class:`~urllib3.fields.RequestField` objects. Supports list of (k, v) tuples and dicts. - """ if isinstance(fields, dict): return ((k, v) for k, v in six.iteritems(fields)) diff --git a/lib/requests/packages/urllib3/poolmanager.py b/lib/requests/packages/urllib3/poolmanager.py index c16519f8..f18ff2bb 100644 --- a/lib/requests/packages/urllib3/poolmanager.py +++ b/lib/requests/packages/urllib3/poolmanager.py @@ -1,5 +1,5 @@ # urllib3/poolmanager.py -# Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt) +# Copyright 2008-2014 Andrey Petrov and contributors (see CONTRIBUTORS.txt) # # This module is part of urllib3 and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -176,7 +176,7 @@ class ProxyManager(PoolManager): Behaves just like :class:`PoolManager`, but sends all requests through the defined proxy, using the CONNECT method for HTTPS URLs. - :param poxy_url: + :param proxy_url: The URL of the proxy to be used. :param proxy_headers: diff --git a/lib/requests/packages/urllib3/util.py b/lib/requests/packages/urllib3/util.py index 46a0c48d..bd266317 100644 --- a/lib/requests/packages/urllib3/util.py +++ b/lib/requests/packages/urllib3/util.py @@ -620,6 +620,11 @@ if SSLContext is not None: # Python 3.2+ """ context = SSLContext(ssl_version) context.verify_mode = cert_reqs + + # Disable TLS compression to migitate CRIME attack (issue #309) + OP_NO_COMPRESSION = 0x20000 + context.options |= OP_NO_COMPRESSION + if ca_certs: try: context.load_verify_locations(ca_certs) diff --git a/lib/requests/sessions.py b/lib/requests/sessions.py index 843e3ae1..425db22c 100644 --- a/lib/requests/sessions.py +++ b/lib/requests/sessions.py @@ -15,9 +15,9 @@ from datetime import datetime from .compat import cookielib, OrderedDict, urljoin, urlparse, builtin_str from .cookies import ( cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) -from .models import Request, PreparedRequest +from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT from .hooks import default_hooks, dispatch_hook -from .utils import to_key_val_list, default_headers +from .utils import to_key_val_list, default_headers, to_native_string from .exceptions import TooManyRedirects, InvalidSchema from .structures import CaseInsensitiveDict @@ -26,13 +26,9 @@ from .adapters import HTTPAdapter from .utils import requote_uri, get_environ_proxies, get_netrc_auth from .status_codes import codes -REDIRECT_STATI = ( - codes.moved, # 301 - codes.found, # 302 - codes.other, # 303 - codes.temporary_moved, # 307 -) -DEFAULT_REDIRECT_LIMIT = 30 + +# formerly defined here, reexposed here for backward compatibility +from .models import REDIRECT_STATI def merge_setting(request_setting, session_setting, dict_class=OrderedDict): @@ -63,6 +59,8 @@ def merge_setting(request_setting, session_setting, dict_class=OrderedDict): if v is None: del merged_setting[k] + merged_setting = dict((k, v) for (k, v) in merged_setting.items() if v is not None) + return merged_setting @@ -89,8 +87,7 @@ class SessionRedirectMixin(object): i = 0 - # ((resp.status_code is codes.see_other)) - while ('location' in resp.headers and resp.status_code in REDIRECT_STATI): + while resp.is_redirect: prepared_request = req.copy() resp.content # Consume socket so it can be released @@ -121,7 +118,7 @@ class SessionRedirectMixin(object): else: url = requote_uri(url) - prepared_request.url = url + prepared_request.url = to_native_string(url) # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4 if (resp.status_code == codes.see_other and @@ -153,11 +150,24 @@ class SessionRedirectMixin(object): except KeyError: pass - extract_cookies_to_jar(prepared_request._cookies, - prepared_request, resp.raw) + extract_cookies_to_jar(prepared_request._cookies, prepared_request, resp.raw) prepared_request._cookies.update(self.cookies) prepared_request.prepare_cookies(prepared_request._cookies) + if 'Authorization' in headers: + # If we get redirected to a new host, we should strip out any + # authentication headers. + original_parsed = urlparse(resp.request.url) + redirect_parsed = urlparse(url) + + if (original_parsed.hostname != redirect_parsed.hostname): + del headers['Authorization'] + + # .netrc might have more auth for us. + new_auth = get_netrc_auth(url) if self.trust_env else None + if new_auth is not None: + prepared_request.prepare_auth(new_auth) + resp = self.send( prepared_request, stream=stream, @@ -291,7 +301,7 @@ class Session(SessionRedirectMixin): def request(self, method, url, params=None, data=None, - headers={'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36'}, + headers=None, cookies=None, files=None, auth=None, @@ -320,7 +330,7 @@ class Session(SessionRedirectMixin): :param auth: (optional) Auth tuple or callable to enable Basic/Digest/Custom HTTP Auth. :param timeout: (optional) Float describing the timeout of the - request. + request in seconds. :param allow_redirects: (optional) Boolean. Set to True by default. :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. @@ -467,8 +477,7 @@ class Session(SessionRedirectMixin): if not isinstance(request, PreparedRequest): raise ValueError('You can only send PreparedRequests.') - # Set up variables needed for resolve_redirects and dispatching of - # hooks + # Set up variables needed for resolve_redirects and dispatching of hooks allow_redirects = kwargs.pop('allow_redirects', True) stream = kwargs.get('stream') timeout = kwargs.get('timeout') @@ -482,8 +491,10 @@ class Session(SessionRedirectMixin): # Start time (approximately) of the request start = datetime.utcnow() + # Send the request r = adapter.send(request, **kwargs) + # Total elapsed time of the request (approximately) r.elapsed = datetime.utcnow() - start @@ -492,15 +503,20 @@ class Session(SessionRedirectMixin): # Persist cookies if r.history: + # If the hooks create history then we want those cookies too for resp in r.history: extract_cookies_to_jar(self.cookies, resp.request, resp.raw) + extract_cookies_to_jar(self.cookies, request, r.raw) # Redirect resolving generator. - gen = self.resolve_redirects(r, request, stream=stream, - timeout=timeout, verify=verify, cert=cert, - proxies=proxies) + gen = self.resolve_redirects(r, request, + stream=stream, + timeout=timeout, + verify=verify, + cert=cert, + proxies=proxies) # Resolve redirects if allowed. history = [resp for resp in gen] if allow_redirects else [] @@ -534,8 +550,10 @@ class Session(SessionRedirectMixin): """Registers a connection adapter to a prefix. Adapters are sorted in descending order by key length.""" + self.adapters[prefix] = adapter keys_to_move = [k for k in self.adapters if len(k) < len(prefix)] + for key in keys_to_move: self.adapters[key] = self.adapters.pop(key) diff --git a/lib/requests/utils.py b/lib/requests/utils.py index 7b7ff0a7..4d648bc5 100644 --- a/lib/requests/utils.py +++ b/lib/requests/utils.py @@ -548,7 +548,7 @@ def default_user_agent(name="python-requests"): def default_headers(): return CaseInsensitiveDict({ 'User-Agent': default_user_agent(), - 'Accept-Encoding': ', '.join(('gzip', 'deflate', 'compress')), + 'Accept-Encoding': ', '.join(('gzip', 'deflate')), 'Accept': '*/*' }) diff --git a/lib/tvdb_api/tvdb_api.py b/lib/tvdb_api/tvdb_api.py index b431f2f6..9d9fcd53 100644 --- a/lib/tvdb_api/tvdb_api.py +++ b/lib/tvdb_api/tvdb_api.py @@ -20,7 +20,6 @@ __version__ = "1.9" import os import time import urllib -import urllib2 import getpass import StringIO import tempfile @@ -39,8 +38,11 @@ try: except ImportError: gzip = None +from lib import requests +from urlparse import urlparse, urlsplit +from lib.cachecontrol.wrapper import CacheControl +from lib.cachecontrol.caches.file_cache import FileCache -from tvdb_cache import CacheHandler from tvdb_ui import BaseUI, ConsoleUI from tvdb_exceptions import (tvdb_error, tvdb_userabort, tvdb_shownotfound, @@ -435,26 +437,13 @@ class Tvdb: if cache is True: self.config['cache_enabled'] = True self.config['cache_location'] = self._getTempDir() - self.urlopener = urllib2.build_opener( - CacheHandler(self.config['cache_location']) - ) elif cache is False: self.config['cache_enabled'] = False - self.urlopener = urllib2.build_opener() # default opener with no caching elif isinstance(cache, basestring): self.config['cache_enabled'] = True self.config['cache_location'] = cache - self.urlopener = urllib2.build_opener( - CacheHandler(self.config['cache_location']) - ) - - elif isinstance(cache, urllib2.OpenerDirector): - # If passed something from urllib2.build_opener, use that - log().debug("Using %r as urlopener" % cache) - self.config['cache_enabled'] = True - self.urlopener = cache else: raise ValueError("Invalid value for Cache %r (type was %s)" % (cache, type(cache))) @@ -501,9 +490,11 @@ class Tvdb: self.config['base_url'] = "http://thetvdb.com" if self.config['search_all_languages']: - self.config['url_getSeries'] = u"%(base_url)s/api/GetSeries.php?seriesname=%%s&language=all" % self.config + self.config['url_getSeries'] = u"%(base_url)s/api/GetSeries.php" % self.config + self.config['params_getSeries'] = {"seriesname": "", "language": "all"} else: - self.config['url_getSeries'] = u"%(base_url)s/api/GetSeries.php?seriesname=%%s&language=%(language)s" % self.config + self.config['url_getSeries'] = u"%(base_url)s/api/GetSeries.php" % self.config + self.config['params_getSeries'] = {"seriesname": "", "language": ""} self.config['url_epInfo'] = u"%(base_url)s/api/%(apikey)s/series/%%s/all/%%s.xml" % self.config self.config['url_epInfo_zip'] = u"%(base_url)s/api/%(apikey)s/series/%%s/all/%%s.zip" % self.config @@ -529,78 +520,29 @@ class Tvdb: return os.path.join(tempfile.gettempdir(), "tvdb_api-%s" % (uid)) - def retry(ExceptionToCheck, default=None, tries=4, delay=3, backoff=2, logger=None): - """Retry calling the decorated function using an exponential backoff. - - http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/ - original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry - - :param ExceptionToCheck: the exception to check. may be a tuple of - excpetions to check - :type ExceptionToCheck: Exception or tuple - :param tries: number of times to try (not retry) before giving up - :type tries: int - :param delay: initial delay between retries in seconds - :type delay: int - :param backoff: backoff multiplier e.g. value of 2 will double the delay - each retry - :type backoff: int - :param logger: logger to use. If None, print - :type logger: logging.Logger instance - """ - def deco_retry(f): - def f_retry(*args, **kwargs): - mtries, mdelay = tries, delay - try_one_last_time = True - while mtries > 1: - try: - print args,kwargs - return f(*args, **kwargs) - try_one_last_time = False - break - except ExceptionToCheck, e: - msg = "%s, Retrying in %d seconds..." % (str(e), mdelay) - if logger: - logger.warning(msg) - else: - print msg - time.sleep(mdelay) - mtries -= 1 - mdelay *= backoff - if try_one_last_time: - try: - return f(*args, **kwargs) - except ExceptionToCheck, e: - return default - return - return f_retry # true decorator - return deco_retry - - @retry(urllib2.URLError, tries=4, delay=3, backoff=2) - def _loadUrl(self, url, recache = False, language=None): + def _loadUrl(self, url, params=None, language=None): global lastTimeout try: log().debug("Retrieving URL %s" % url) - resp = self.urlopener.open(url) - if 'x-local-cache' in resp.headers: - log().debug("URL %s was cached in %s" % ( - url, - resp.headers['x-local-cache']) - ) - if recache: - log().debug("Attempting to recache %s" % url) - resp.recache() - except (IOError, urllib2.URLError), errormsg: - if not str(errormsg).startswith('HTTP Error'): - lastTimeout = datetime.datetime.now() - raise tvdb_error("Could not connect to server: %s" % (errormsg)) - + # cacheControl + if self.config['cache_enabled']: + sess = CacheControl(requests.Session(), cache=FileCache(self.config['cache_location'])) + else: + sess = requests.Session() + + # get response from TVRage + resp = sess.get(url, params=params) + except Exception, e: + if not str(e).startswith('HTTP Error'): + lastTimeout = datetime.datetime.now() + raise tvdb_error("Could not connect to server: %s" % (e)) + # handle gzipped content, # http://dbr.lighthouseapp.com/projects/13342/tickets/72-gzipped-data-patch if 'gzip' in resp.headers.get("Content-Encoding", ''): if gzip: - stream = StringIO.StringIO(resp.read()) + stream = StringIO.StringIO(resp.content) gz = gzip.GzipFile(fileobj=stream) return gz.read() @@ -611,26 +553,24 @@ class Tvdb: # TODO: The zip contains actors.xml and banners.xml, which are currently ignored [GH-20] log().debug("We recived a zip file unpacking now ...") zipdata = StringIO.StringIO() - zipdata.write(resp.read()) + zipdata.write(resp.content) myzipfile = zipfile.ZipFile(zipdata) return myzipfile.read('%s.xml' % language) except zipfile.BadZipfile: - if 'x-local-cache' in resp.headers: - resp.delete_cache() raise tvdb_error("Bad zip file received from thetvdb.com, could not read it") - return resp.read() + return resp.content - def _getetsrc(self, url, language=None): + def _getetsrc(self, url, params=None, language=None): """Loads a URL using caching, returns an ElementTree of the source """ - src = self._loadUrl(url, language=language) + src = self._loadUrl(url, params=params, language=language) try: # TVDB doesn't sanitize \r (CR) from user input in some fields, # remove it to avoid errors. Change from SickBeard, from will14m return ElementTree.fromstring(src.rstrip("\r")) except SyntaxError: - src = self._loadUrl(url, recache=True, language=language) + src = self._loadUrl(url, params=None, language=language) try: return ElementTree.fromstring(src.rstrip("\r")) except SyntaxError, exceptionmsg: @@ -694,7 +634,8 @@ class Tvdb: """ series = urllib.quote(series.encode("utf-8")) log().debug("Searching for show %s" % series) - seriesEt = self._getetsrc(self.config['url_getSeries'] % (series)) + self.config['params_getSeries']['seriesname'] = series + seriesEt = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries']) allSeries = [] for series in seriesEt: result = dict((k.tag.lower(), k.text) for k in series.getchildren()) diff --git a/lib/tvrage_api/tvrage_api.py b/lib/tvrage_api/tvrage_api.py index 79d2bad8..9eed27a0 100644 --- a/lib/tvrage_api/tvrage_api.py +++ b/lib/tvrage_api/tvrage_api.py @@ -16,7 +16,6 @@ import os import re import time import urllib -import urllib2 import getpass import tempfile import warnings @@ -28,10 +27,12 @@ try: except ImportError: import xml.etree.ElementTree as ElementTree -from lib import requests from lib.dateutil.parser import parse -from tvrage_cache import CacheHandler +from lib import requests +from lib.cachecontrol.wrapper import CacheControl +from lib.cachecontrol.caches.file_cache import FileCache + from tvrage_ui import BaseUI from tvrage_exceptions import (tvrage_error, tvrage_userabort, tvrage_shownotfound, tvrage_seasonnotfound, tvrage_episodenotfound, tvrage_attributenotfound) @@ -276,26 +277,13 @@ class TVRage: if cache is True: self.config['cache_enabled'] = True self.config['cache_location'] = self._getTempDir() - self.urlopener = urllib2.build_opener( - CacheHandler(self.config['cache_location']) - ) elif cache is False: self.config['cache_enabled'] = False - self.urlopener = urllib2.build_opener() # default opener with no caching elif isinstance(cache, basestring): self.config['cache_enabled'] = True self.config['cache_location'] = cache - self.urlopener = urllib2.build_opener( - CacheHandler(self.config['cache_location']) - ) - - elif isinstance(cache, urllib2.OpenerDirector): - # If passed something from urllib2.build_opener, use that - log().debug("Using %r as urlopener" % cache) - self.config['cache_enabled'] = True - self.urlopener = cache else: raise ValueError("Invalid value for Cache %r (type was %s)" % (cache, type(cache))) @@ -336,13 +324,17 @@ class TVRage: # The following url_ configs are based of the # http://tvrage.com/wiki/index.php/Programmers_API + self.config['base_url'] = "http://services.tvrage.com" - self.config['url_getSeries'] = u"%(base_url)s/myfeeds/search.php?key=%(apikey)s&show=%%s" % self.config + self.config['url_getSeries'] = u"%(base_url)s/myfeeds/search.php" % self.config + self.config['params_getSeries'] = {"key": self.config['apikey'], "show": ""} - self.config['url_epInfo'] = u"%(base_url)s/myfeeds/episode_list.php?key=%(apikey)s&sid=%%s" % self.config + self.config['url_epInfo'] = u"%(base_url)s/myfeeds/episode_list.php" % self.config + self.config['params_epInfo'] = {"key": self.config['apikey'], "sid": ""} - self.config['url_seriesInfo'] = u"%(base_url)s/myfeeds/showinfo.php?key=%(apikey)s&sid=%%s" % self.config + self.config['url_seriesInfo'] = u"%(base_url)s/myfeeds/showinfo.php" % self.config + self.config['params_seriesInfo'] = {"key": self.config['apikey'], "sid": ""} def _getTempDir(self): """Returns the [system temp dir]/tvrage_api-u501 (or @@ -359,76 +351,27 @@ class TVRage: return os.path.join(tempfile.gettempdir(), "tvrage_api-%s" % (uid)) - def retry(ExceptionToCheck, default=None, tries=4, delay=3, backoff=2, logger=None): - """Retry calling the decorated function using an exponential backoff. - - http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/ - original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry - - :param ExceptionToCheck: the exception to check. may be a tuple of - excpetions to check - :type ExceptionToCheck: Exception or tuple - :param tries: number of times to try (not retry) before giving up - :type tries: int - :param delay: initial delay between retries in seconds - :type delay: int - :param backoff: backoff multiplier e.g. value of 2 will double the delay - each retry - :type backoff: int - :param logger: logger to use. If None, print - :type logger: logging.Logger instance - """ - def deco_retry(f): - def f_retry(*args, **kwargs): - mtries, mdelay = tries, delay - try_one_last_time = True - while mtries > 1: - try: - print args,kwargs - return f(*args, **kwargs) - try_one_last_time = False - break - except ExceptionToCheck, e: - msg = "%s, Retrying in %d seconds..." % (str(e), mdelay) - if logger: - logger.warning(msg) - else: - print msg - time.sleep(mdelay) - mtries -= 1 - mdelay *= backoff - if try_one_last_time: - try: - return f(*args, **kwargs) - except ExceptionToCheck, e: - return default - return - return f_retry # true decorator - return deco_retry - - @retry(urllib2.URLError, tries=4, delay=3, backoff=2) - def _loadUrl(self, url, recache = False): + def _loadUrl(self, url, params=None): global lastTimeout try: log().debug("Retrieving URL %s" % url) - #resp = self.urlopener.open(url) - resp = requests.get(url) - if 'x-local-cache' in resp.headers: - log().debug("URL %s was cached in %s" % ( - url, - resp.headers['x-local-cache']) - ) - if recache: - log().debug("Attempting to recache %s" % url) - resp.recache() - except (IOError, urllib2.URLError), errormsg: - if not str(errormsg).startswith('HTTP Error'): + + # cacheControl + if self.config['cache_enabled']: + sess = CacheControl(requests.Session(), cache=FileCache(self.config['cache_location'])) + else: + sess = requests.Session() + + # get response from TVRage + resp = sess.get(url, params=params) + except Exception, e: + if not str(e).startswith('HTTP Error'): lastTimeout = dt.datetime.now() - raise tvrage_error("Could not connect to server: %s" % (errormsg)) + raise tvrage_error("Could not connect to server: %s" % (e)) return resp.content - def _getetsrc(self, url): + def _getetsrc(self, url, params=None): """Loads a URL using caching, returns an ElementTree of the source """ reDict = { @@ -449,7 +392,7 @@ class TVRage: } robj = re.compile('|'.join(reDict.keys())) - src = self._loadUrl(url) + src = self._loadUrl(url, params) try: # TVRAGE doesn't sanitize \r (CR) from user input in some fields, # remove it to avoid errors. Change from SickBeard, from will14m @@ -459,24 +402,30 @@ class TVRage: elm.tag = robj.sub(lambda m: reDict[m.group(0)], elm.tag) if elm.tag in 'firstaired': - fixDate = parse(elm.text) - value = fixDate.strftime("%Y-%m-%d") - - elm.text = value + if elm.text is "0000-00-00": + elm.text = str(dt.date.fromordinal(1)) + try: + fixDate = parse(elm.text, fuzzy=True) + elm.text = fixDate.strftime("%Y-%m-%d") + except: + pass return ElementTree.fromstring(ElementTree.tostring(xml)) except SyntaxError: - src = self._loadUrl(url, recache=True) + src = self._loadUrl(url, params) try: xml = ElementTree.fromstring(src.rstrip("\r")) tree = ElementTree.ElementTree(xml) for elm in tree.iter(): elm.tag = robj.sub(lambda m: reDict[m.group(0)], elm.tag) - if elm.tag in 'firstaired': - fixDate = parse(elm.text) - value = fixDate.strftime("%Y-%m-%d") - - elm.text = value + if elm.tag in 'firstaired' and elm.text: + if elm.text is "0000-00-00": + elm.text = str(dt.date.fromordinal(1)) + try: + fixDate = parse(elm.text, fuzzy=True) + elm.text = fixDate.strftime("%Y-%m-%d") + except: + pass return ElementTree.fromstring(ElementTree.tostring(xml)) except SyntaxError, exceptionmsg: errormsg = "There was an error with the XML retrieved from tvrage.com:\n%s" % ( @@ -538,7 +487,8 @@ class TVRage: """ series = urllib.quote(series.encode("utf-8")) log().debug("Searching for show %s" % series) - seriesEt = self._getetsrc(self.config['url_getSeries'] % (series)) + self.config['params_getSeries']['show'] = series + seriesEt = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries']) allSeries = [] seriesResult = {} for series in seriesEt: @@ -580,8 +530,10 @@ class TVRage: # Parse show information log().debug('Getting all series data for %s' % (sid)) + self.config['params_seriesInfo']['sid'] = sid seriesInfoEt = self._getetsrc( - self.config['url_seriesInfo'] % (sid) + self.config['url_seriesInfo'], + self.config['params_seriesInfo'] ) for curInfo in seriesInfoEt: @@ -610,8 +562,8 @@ class TVRage: # Parse episode data log().debug('Getting all episodes of %s' % (sid)) - url = self.config['url_epInfo'] % (sid) - epsEt = self._getetsrc(url) + self.config['params_epInfo']['sid'] = sid + epsEt = self._getetsrc(self.config['url_epInfo'], self.config['params_epInfo']) for cur_list in epsEt.findall("Episodelist"): for cur_seas in cur_list: try: diff --git a/sickbeard/indexers/generic.py b/sickbeard/indexers/generic.py index 531d625a..353d4e0c 100644 --- a/sickbeard/indexers/generic.py +++ b/sickbeard/indexers/generic.py @@ -15,6 +15,9 @@ # # You should have received a copy of the GNU General Public License # along with Sick Beard. If not, see . +import os + +import sickbeard class GenericIndexer(object): def __init__(self, indexer): @@ -23,10 +26,10 @@ class GenericIndexer(object): INDEXER_TVDB = 'Tvdb' INDEXER_TVRAGE = 'TVRage' - INDEXER_NAME = {} - INDEXER_NAME[INDEXER_NONE] = '' - INDEXER_NAME[INDEXER_TVDB] = 'theTVDB' - INDEXER_NAME[INDEXER_TVRAGE] = 'TVRage' + INDEXERS = {} + INDEXERS[INDEXER_NONE] = '' + INDEXERS[INDEXER_TVDB] = 'theTVDB' + INDEXERS[INDEXER_TVRAGE] = 'TVRage' INDEXER_API_KEY = {} INDEXER_API_KEY[INDEXER_NONE] = '' @@ -57,6 +60,8 @@ class GenericIndexer(object): 'tr': 21, 'pl': 18, 'fr': 17, 'hr': 31, 'de': 14, 'da': 10, 'fi': 11, 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32, 'sv': 8, 'sl': 30} - self.config['base_url'] = INDEXER_BASEURL[indexer] - self.config['api_parms'] = INDEXER_API_PARMS[indexer] - self.config['name'] = INDEXER_NAME[indexer] \ No newline at end of file + self.base_url = INDEXER_BASEURL[indexer] + self.api_parms = INDEXER_API_PARMS[indexer] + self.indexerName = INDEXERS[indexer] + self.cache = os.path.join(sickbeard.CACHE_DIR, indexer) + self.indexers = [indexer for indexer in INDEXERS] \ No newline at end of file diff --git a/sickbeard/indexers/indexer_api.py b/sickbeard/indexers/indexer_api.py index 77597b8c..6f47f71a 100644 --- a/sickbeard/indexers/indexer_api.py +++ b/sickbeard/indexers/indexer_api.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with Sick Beard. If not, see . import os +import datetime import sickbeard import generic @@ -25,19 +26,18 @@ from lib.tvdb_api.tvdb_api import Tvdb from lib.tvrage_api.tvrage_api import TVRage class indexerApi(generic.GenericIndexer): - def __init__(self, *args, **kwargs): - indexer = kwargs.pop('indexer',None) + def __init__(self, indexer=None, *args, **kwargs): super(indexerApi, self).__init__(indexer) - self.name = self.config['name'] + self.name = self.indexerName if indexer: - self.config['api_parms'].update(**kwargs) + self.api_parms.update(**kwargs) if sickbeard.CACHE_DIR: - self.config['api_parms']['cache'] = os.path.join(sickbeard.CACHE_DIR, indexer) + self.api_parms['cache'] = self.cache # wrap the indexer API object and return it back - self._wrapped = eval(indexer)(*args, **self.config['api_parms']) + self._wrapped = eval(indexer)(*args, **self.api_parms) def __getattr__(self, attr): return getattr(self._wrapped, attr) diff --git a/sickbeard/indexers/indexer_config.py b/sickbeard/indexers/indexer_config.py deleted file mode 100644 index 3db1b41a..00000000 --- a/sickbeard/indexers/indexer_config.py +++ /dev/null @@ -1,29 +0,0 @@ -INDEXER_TVDB = 'Tvdb' -INDEXER_TVRAGE = 'TVRage' - -INDEXER_API_KEY = {} -INDEXER_API_KEY[INDEXER_TVDB] = '9DAF49C96CBF8DAC' -INDEXER_API_KEY[INDEXER_TVRAGE] = 'Uhewg1Rr0o62fvZvUIZt' - -INDEXER_BASEURL = {} -INDEXER_BASEURL[INDEXER_TVDB] = 'http://thetvdb.com/api/' + INDEXER_API_KEY[INDEXER_TVDB] -INDEXER_BASEURL[INDEXER_TVRAGE] = 'http://tvrage.com/feeds/' + INDEXER_API_KEY[INDEXER_TVRAGE] - -INDEXER_API_PARMS = {} -INDEXER_API_PARMS[INDEXER_TVDB] = {'apikey': INDEXER_API_KEY[INDEXER_TVDB], - 'language': 'en', - 'useZip': True} - -INDEXER_API_PARMS[INDEXER_TVRAGE] = {'apikey': INDEXER_API_KEY[INDEXER_TVRAGE], - 'language': 'en'} - - -INDEXER_CONFIG = {} -INDEXER_CONFIG['valid_languages'] = [ - "da", "fi", "nl", "de", "it", "es", "fr","pl", "hu","el","tr", - "ru","he","ja","pt","zh","cs","sl", "hr","ko","en","sv","no"] - -INDEXER_CONFIG['langabbv_to_id'] = {'el': 20, 'en': 7, 'zh': 27, -'it': 15, 'cs': 28, 'es': 16, 'ru': 22, 'nl': 13, 'pt': 26, 'no': 9, -'tr': 21, 'pl': 18, 'fr': 17, 'hr': 31, 'de': 14, 'da': 10, 'fi': 11, -'hu': 19, 'ja': 25, 'he': 24, 'ko': 32, 'sv': 8, 'sl': 30} \ No newline at end of file diff --git a/sickbeard/indexers/test/test.py b/sickbeard/indexers/test/test.py index e73c5bbb..75bc58c2 100644 --- a/sickbeard/indexers/test/test.py +++ b/sickbeard/indexers/test/test.py @@ -2,30 +2,19 @@ from __future__ import with_statement import unittest -import sqlite3 - import sys import os.path sys.path.append(os.path.abspath('..')) -sys.path.append(os.path.abspath('../lib')) +sys.path.append(os.path.abspath('../../../lib')) -import sickbeard -import shutil - -from sickbeard import encodingKludge as ek, providers, tvcache -from sickbeard import db -from sickbeard.databases import mainDB -from sickbeard.databases import cache_db - - -from indexer_api import indexerApi -from indexer_exceptions import indexer_exception +from sickbeard.indexers.indexer_api import indexerApi +from sickbeard.indexers.indexer_exceptions import indexer_exception class APICheck(unittest.TestCase): - indexer_id = 258171 - indexer = 'Tvdb' + indexer_id = 'Continum' + indexer = 'TVRage' # Set our common indexer_api options here - INDEXER_API_PARMS = {'apikey': '9DAF49C96CBF8DAC', + INDEXER_API_PARMS = {'apikey': 'Uhewg1Rr0o62fvZvUIZt', 'language': 'en', 'useZip': True} @@ -34,11 +23,9 @@ class APICheck(unittest.TestCase): lindexer_api_parms = INDEXER_API_PARMS.copy() try: - imdbid = " " - showurl = indexerApi(**lindexer_api_parms).config['base_url'] + indexer_id + '/all/en.zip' - t = indexerApi().config['valid_languages'] - t = indexerApi(**lindexer_api_parms) - myEp = t[258171] +# showurl = indexerApi(**lindexer_api_parms).config['base_url'] + str(indexer_id) + '/all/en.zip' + t = indexerApi(cache=True, **lindexer_api_parms) + myEp = t[indexer_id] if getattr(myEp, 'seriesname', None) is not None: print "FOUND" diff --git a/sickbeard/metadata/xbmc_12plus.py b/sickbeard/metadata/xbmc_12plus.py index d0b4d5da..063251ed 100644 --- a/sickbeard/metadata/xbmc_12plus.py +++ b/sickbeard/metadata/xbmc_12plus.py @@ -153,7 +153,7 @@ class XBMC_12PlusMetadata(generic.GenericMetadata): episodeguideurl = etree.SubElement(episodeguide, "url") episodeguideurl2 = etree.SubElement(tv_node, "episodeguideurl") if getattr(myShow, 'id', None) is not None: - showurl = t.config['base_url'] + myShow["id"] + '/all/en.zip' + showurl = t.base_url + myShow["id"] + '/all/en.zip' episodeguideurl.text = showurl episodeguideurl2.text = showurl diff --git a/sickbeard/showUpdater.py b/sickbeard/showUpdater.py index 44994ee6..d2fa2f87 100644 --- a/sickbeard/showUpdater.py +++ b/sickbeard/showUpdater.py @@ -28,6 +28,7 @@ from sickbeard.exceptions import ex from sickbeard import encodingKludge as ek from sickbeard import db +from indexers.indexer_api import indexerApi class ShowUpdater(): @@ -39,7 +40,7 @@ class ShowUpdater(): # update at 3 AM run_updater_time = datetime.time(hour=3) - update_datetime = datetime.datetime.today() + update_datetime = datetime.time.today() update_date = update_datetime.date() logger.log(u"Checking update interval", logger.DEBUG) @@ -54,29 +55,30 @@ class ShowUpdater(): # clean out cache directory, remove everything > 12 hours old if sickbeard.CACHE_DIR: - cache_dir = sickbeard.INDEXER_API_PARMS['cache'] - logger.log(u"Trying to clean cache folder " + cache_dir) + for indexer in indexerApi().indexers: + cache_dir = indexerApi(indexer=indexer).cache + logger.log(u"Trying to clean cache folder " + cache_dir) - # Does our cache_dir exists - if not ek.ek(os.path.isdir, cache_dir): - logger.log(u"Can't clean " + cache_dir + " if it doesn't exist", logger.WARNING) - else: - max_age = datetime.timedelta(hours=12) - # Get all our cache files - cache_files = ek.ek(os.listdir, cache_dir) + # Does our cache_dir exists + if not ek.ek(os.path.isdir, cache_dir): + logger.log(u"Can't clean " + cache_dir + " if it doesn't exist", logger.WARNING) + else: + max_age = datetime.timedelta(hours=12) + # Get all our cache files + cache_files = ek.ek(os.listdir, cache_dir) - for cache_file in cache_files: - cache_file_path = ek.ek(os.path.join, cache_dir, cache_file) + for cache_file in cache_files: + cache_file_path = ek.ek(os.path.join, cache_dir, cache_file) - if ek.ek(os.path.isfile, cache_file_path): - cache_file_modified = datetime.datetime.fromtimestamp(ek.ek(os.path.getmtime, cache_file_path)) + if ek.ek(os.path.isfile, cache_file_path): + cache_file_modified = datetime.datetime.fromtimestamp(ek.ek(os.path.getmtime, cache_file_path)) - if update_datetime - cache_file_modified > max_age: - try: - ek.ek(os.remove, cache_file_path) - except OSError, e: - logger.log(u"Unable to clean " + cache_dir + ": " + repr(e) + " / " + str(e), logger.WARNING) - break + if update_datetime - cache_file_modified > max_age: + try: + ek.ek(os.remove, cache_file_path) + except OSError, e: + logger.log(u"Unable to clean " + cache_dir + ": " + repr(e) + " / " + str(e), logger.WARNING) + break # select 10 'Ended' tv_shows updated more than 90 days ago to include in this update stale_should_update = [] diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py index 375b839a..2c7f798b 100644 --- a/sickbeard/show_queue.py +++ b/sickbeard/show_queue.py @@ -451,7 +451,7 @@ class QueueItemUpdate(ShowQueueItem): logger.log(u"Retrieving show info from " + self.show.indexer + "", logger.DEBUG) try: - self.show.loadFromIndexer(cache=not self.force) + self.show.loadFromIndexer(cache=self.force) except indexer_exceptions.indexer_error, e: logger.log(u"Unable to contact " + self.show.indexer + ", aborting: " + ex(e), logger.WARNING) return