Refactoring and adding tests

This commit is contained in:
Michael Lazar
2017-09-13 23:35:40 -04:00
parent 5e82811918
commit 031b58b3b4
9 changed files with 2500 additions and 109 deletions

View File

@@ -36,8 +36,9 @@ from . import packages
from .packages import praw
from .config import Config, copy_default_config, copy_default_mailcap
from .theme import Theme
from .oauth import OAuthHelper, OAuthRateLimiter
from .oauth import OAuthHelper
from .terminal import Terminal
from .content import RequestHeaderRateLimiter
from .objects import curses_session, patch_webbrowser
from .subreddit_page import SubredditPage
from .exceptions import ConfigError
@@ -177,7 +178,12 @@ def main():
reddit = praw.Reddit(user_agent=user_agent,
decode_html_entities=False,
disable_update_check=True,
handler=OAuthRateLimiter())
handler=RequestHeaderRateLimiter())
# Dial the request cache up from 30 seconds to 5 minutes
# I'm trying this out to make navigation back and forth
# between pages quicker, it may still need to be fine tuned.
reddit.config.api_request_delay = 300
# Authorize on launch if the refresh token is present
oauth = OAuthHelper(reddit, term, config)

View File

@@ -2,8 +2,10 @@
from __future__ import unicode_literals
import re
import time
import logging
from datetime import datetime
from timeit import default_timer as timer
import six
from kitchen.text.display import wrap
@@ -11,6 +13,8 @@ from kitchen.text.display import wrap
from . import exceptions
from .packages import praw
from .packages.praw.errors import InvalidSubreddit
from .packages.praw.helpers import normalize_url
from .packages.praw.handlers import DefaultHandler
_logger = logging.getLogger(__name__)
@@ -777,3 +781,172 @@ class SubscriptionContent(Content):
data['h_offset'] = 0
return data
class RequestHeaderRateLimiter(DefaultHandler):
"""Custom PRAW request handler for rate-limiting requests.
This is an alternative to PRAW 3's DefaultHandler that uses
Reddit's modern API guidelines to rate-limit requests based
on the X-Ratelimit-* headers returned from Reddit. Most of
these methods are copied from or derived from the DefaultHandler.
References:
https://github.com/reddit/reddit/wiki/API
https://github.com/praw-dev/prawcore/blob/master/prawcore/rate_limit.py
"""
def __init__(self):
# In PRAW's convention, these variables were bound to the
# class so the cache could be shared among all of the ``reddit``
# instances. In RTV's use-case there is only ever a single reddit
# instance so it made sense to clean up the globals and transfer them
# to method variables
self.cache = {}
self.cache_hit_callback = None
self.timeouts = {}
# These are used for the header rate-limiting
self.used = None
self.remaining = None
self.seconds_to_reset = None
self.next_request_timestamp = None
super(RequestHeaderRateLimiter, self).__init__()
def _delay(self):
"""
Pause before making the next HTTP request.
"""
if self.next_request_timestamp is None:
return
sleep_seconds = self.next_request_timestamp - time.time()
if sleep_seconds <= 0:
return
time.sleep(sleep_seconds)
def _update(self, response_headers):
"""
Update the state of the rate limiter based on the response headers:
X-Ratelimit-Used: Approximate number of requests used this period
X-Ratelimit-Remaining: Approximate number of requests left to use
X-Ratelimit-Reset: Approximate number of seconds to end of period
PRAW 5's rate limiting logic is structured for making hundreds of
evenly-spaced API requests, which makes sense for running something
like a bot or crawler.
This handler's logic, on the other hand, is geared more towards
interactive usage. It allows for short, sporadic bursts of requests.
The assumption is that actual users browsing reddit shouldn't ever be
in danger of hitting the rate limit. If they do hit the limit, they
will be cutoff until the period resets.
"""
if 'x-ratelimit-remaining' not in response_headers:
# This could be because the API returned an error response, or it
# could be because we're using something like read-only credentials
# which Reddit doesn't appear to care about rate limiting.
return
self.used = float(response_headers['x-ratelimit-used'])
self.remaining = float(response_headers['x-ratelimit-remaining'])
self.seconds_to_reset = int(response_headers['x-ratelimit-reset'])
_logger.debug('Rate limit: %s used, %s remaining, %s reset',
self.used, self.remaining, self.seconds_to_reset)
if self.remaining <= 0:
self.next_request_timestamp = time.time() + self.seconds_to_reset
else:
self.next_request_timestamp = None
def _clear_timeouts(self, cache_timeout):
"""
Clear the cache of timed out results.
"""
for key in list(self.timeouts):
if timer() - self.timeouts[key] > cache_timeout:
del self.timeouts[key]
del self.cache[key]
def clear_cache(self):
"""Remove all items from the cache."""
self.cache = {}
self.timeouts = {}
def evict(self, urls):
"""Remove items from cache matching URLs.
Return the number of items removed.
"""
if isinstance(urls, six.text_type):
urls = [urls]
urls = set(normalize_url(url) for url in urls)
retval = 0
for key in list(self.cache):
if key[0] in urls:
retval += 1
del self.cache[key]
del self.timeouts[key]
return retval
def request(self, _cache_key, _cache_ignore, _cache_timeout, **kwargs):
"""
This is a wrapper function that handles the caching of the request.
See DefaultHandler.with_cache for reference.
"""
if _cache_key:
# Pop the request's session cookies from the cache key.
# These appear to be unreliable and change with every
# request. Also, with the introduction of OAuth I don't think
# that cookies are being used to store anything that
# differentiates API requests anyways
url, items = _cache_key
_cache_key = (url, (items[0], items[1], items[3], items[4]))
if kwargs['request'].method != 'GET':
# I added this check for RTV, I have no idea why PRAW would ever
# want to cache POST/PUT/DELETE requests
_cache_ignore = True
if _cache_ignore:
return self._request(**kwargs)
self._clear_timeouts(_cache_timeout)
if _cache_key in self.cache:
if self.cache_hit_callback:
self.cache_hit_callback(_cache_key)
return self.cache[_cache_key]
result = self._request(**kwargs)
# The handlers don't call `raise_for_status` so we need to ignore
# status codes that will result in an exception that should not be
# cached.
if result.status_code not in (200, 302):
return result
self.timeouts[_cache_key] = timer()
self.cache[_cache_key] = result
return result
def _request(self, request, proxies, timeout, verify, **_):
"""
This is where we apply rate limiting and make the HTTP request.
"""
settings = self.http.merge_environment_settings(
request.url, proxies, False, verify, None)
self._delay()
response = self.http.send(
request, timeout=timeout, allow_redirects=False, **settings)
self._update(response.headers)
return response

View File

@@ -17,7 +17,6 @@ from . import docs
from .config import TEMPLATES
from .exceptions import InvalidRefreshToken
from .packages.praw.errors import HTTPException, OAuthException
from .packages.praw.handlers import DefaultHandler
_logger = logging.getLogger(__name__)
@@ -228,104 +227,3 @@ class OAuthHelper(object):
def clear_oauth_data(self):
self.reddit.clear_authentication()
self.config.delete_refresh_token()
def fix_cache(func):
"""
This is a shim around PRAW's 30 second page cache that attempts
to address broken behavior that hasn't been fixed because PRAW 3
is deprecated.
"""
def wraps(self, _cache_key, _cache_ignore, *args, **kwargs):
if _cache_key:
# Pop the request's session cookies from the cache key.
# These appear to be unreliable and change with every
# request. Also, with the introduction of OAuth I don't think
# that cookies are being used to store anything that
# differentiates API requests anyways
url, items = _cache_key
_cache_key = (url, (items[0], items[1], items[3], items[4]))
if kwargs['request'].method != 'GET':
# Why were POST/PUT/DELETE requests ever being cached???
_cache_ignore = True
return func(self, _cache_key, _cache_ignore, *args, **kwargs)
return wraps
class OAuthRateLimiter(DefaultHandler):
"""Custom PRAW request handler for rate-limiting requests.
This is an alternative to PRAW 3's DefaultHandler that uses
Reddit's modern API guidelines to rate-limit requests based
on the X-Ratelimit-* headers returned from Reddit.
References:
https://github.com/reddit/reddit/wiki/API
https://github.com/praw-dev/prawcore/blob/master/prawcore/rate_limit.py
"""
next_request_timestamp = None
def delay(self):
"""
Pause before making the next HTTP request.
"""
if self.next_request_timestamp is None:
return
sleep_seconds = self.next_request_timestamp - time.time()
if sleep_seconds <= 0:
return
time.sleep(sleep_seconds)
def update(self, response_headers):
"""
Update the state of the rate limiter based on the response headers:
X-Ratelimit-Used: Approximate number of requests used this period
X-Ratelimit-Remaining: Approximate number of requests left to use
X-Ratelimit-Reset: Approximate number of seconds to end of period
PRAW 5's rate limiting logic is structured for making hundreds of
evenly-spaced API requests, which makes sense for running something
like a bot or crawler.
This handler's logic, on the other hand, is geared more towards
interactive usage. It allows for short, sporadic bursts of requests.
The assumption is that actual users browsing reddit shouldn't ever be
in danger of hitting the rate limit. If they do hit the limit, they
will be cutoff until the period resets.
"""
if 'x-ratelimit-remaining' not in response_headers:
# This could be because the API returned an error response, or it
# could be because we're using something like read-only credentials
# which Reddit doesn't appear to care about rate limiting.
return
used = float(response_headers['x-ratelimit-used'])
remaining = float(response_headers['x-ratelimit-remaining'])
seconds_to_reset = int(response_headers['x-ratelimit-reset'])
_logger.debug('Rate limit: %s used, %s remaining, %s reset',
used, remaining, seconds_to_reset)
if remaining <= 0:
self.next_request_timestamp = time.time() + seconds_to_reset
else:
self.next_request_timestamp = None
@fix_cache
@DefaultHandler.with_cache
def request(self, request, proxies, timeout, verify, **_):
settings = self.http.merge_environment_settings(
request.url, proxies, False, verify, None)
self.delay()
response = self.http.send(
request, timeout=timeout, allow_redirects=False, **settings)
self.update(response.headers)
return response

View File

@@ -0,0 +1,242 @@
interactions:
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Connection: [keep-alive]
User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit']
method: GET
uri: https://api.reddit.com/r/python/.json
response:
body:
string: !!binary |
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
um2oFQgSSfKaQa9QkM4BmL/4vywoXVwfDgEA
headers:
Accept-Ranges: [bytes]
Connection: [keep-alive]
Content-Encoding: [gzip]
Content-Length: ['10857']
Content-Type: [application/json; charset=UTF-8]
Date: ['Thu, 14 Sep 2017 03:12:39 GMT']
Server: [snooserv]
Set-Cookie: ['loid=00000000000drard7x.2.1505358759424.Z0FBQUFBQlp1Zk9uRlVnTGJkUHdhMnowYk56WjdsM1BCdHJOVUVUOXhfQkVEZHZacGJtbTFyd2EzV2Vab2lNV0VNTEVkZ2xOUENLXzVpU25obVV4eW13TGNDRS10SVlwM3I5bHZMcXA3LWRuSUxBcWNrTHVtTWFJTGEzN21TMzJuVzNYdDAxNU8xVWM;
Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 14-Sep-2019 03:12:39
GMT; secure', 'session_tracker=kUDpBtJiJyUWSfxs6o.0.1505358759418.Z0FBQUFBQlp1Zk9uakFjNEJOQ2xHVF9NWXJTTjE0VmV0NWpha2VRVnNPanBTLUl6SDBFV1hHZ2VYRDFPVEVqMUgwVGU5d2lhZ193aFNfc1F6b2thQ1prcTc4S3AxS2N2ZXdRd25PcVNVd2FqM0pPYW43Qm13anNLelJWNS1FdzRzRDZNenU0d1ZWRUc;
Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 14-Sep-2017 05:12:39
GMT; secure', edgebucket=OZ04pRZAsfxvngtfqe; Domain=reddit.com; Max-Age=63071999;
Path=/; secure]
Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload]
Vary: [accept-encoding]
Via: [1.1 varnish]
X-Cache: [MISS]
X-Cache-Hits: ['0']
X-Moose: [majestic]
X-Served-By: [cache-ord1724-ORD]
X-Timer: ['S1505358759.392876,VS0,VE159']
access-control-allow-origin: ['*']
access-control-expose-headers: ['X-Reddit-Tracking, X-Moose']
cache-control: ['max-age=0, must-revalidate']
set-cookie: ['loid=00000000000drard7x.2.1505358759424.Z0FBQUFBQlp1Zk9uRlVnTGJkUHdhMnowYk56WjdsM1BCdHJOVUVUOXhfQkVEZHZacGJtbTFyd2EzV2Vab2lNV0VNTEVkZ2xOUENLXzVpU25obVV4eW13TGNDRS10SVlwM3I5bHZMcXA3LWRuSUxBcWNrTHVtTWFJTGEzN21TMzJuVzNYdDAxNU8xVWM;
Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 14-Sep-2019 03:12:39
GMT; secure', 'session_tracker=kUDpBtJiJyUWSfxs6o.0.1505358759418.Z0FBQUFBQlp1Zk9uakFjNEJOQ2xHVF9NWXJTTjE0VmV0NWpha2VRVnNPanBTLUl6SDBFV1hHZ2VYRDFPVEVqMUgwVGU5d2lhZ193aFNfc1F6b2thQ1prcTc4S3AxS2N2ZXdRd25PcVNVd2FqM0pPYW43Qm13anNLelJWNS1FdzRzRDZNenU0d1ZWRUc;
Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 14-Sep-2017 05:12:39
GMT; secure', edgebucket=OZ04pRZAsfxvngtfqe; Domain=reddit.com; Max-Age=63071999;
Path=/; secure]
x-content-type-options: [nosniff]
x-frame-options: [SAMEORIGIN]
x-reddit-tracking: ['https://pixel.redditmedia.com/pixel/of_destiny.png?v=V0k5ZJqU%2FwpKysQ36p0adKUNzpijYRyqyHdid2vPZOYUaJl8oxXeCjDNYNSh%2FwOjHIqyvz4njhQ%3D']
x-ua-compatible: [IE=edge]
x-xss-protection: [1; mode=block]
status: {code: 200, message: OK}
version: 1

View File

@@ -0,0 +1,588 @@
interactions:
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Connection: [keep-alive]
User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit']
method: GET
uri: https://api.reddit.com/r/python/.json
response:
body:
string: !!binary |
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
NHJedw0BAA==
headers:
Accept-Ranges: [bytes]
Connection: [keep-alive]
Content-Encoding: [gzip]
Content-Length: ['10723']
Content-Type: [application/json; charset=UTF-8]
Date: ['Thu, 14 Sep 2017 03:34:25 GMT']
Server: [snooserv]
Set-Cookie: ['loid=00000000000drcw01i.2.1505360065178.Z0FBQUFBQlp1ZmpCZnJBMlhNcFVMa0RON1lKNzlDUU5FelFZenQySllVckJKZlROOHZEbTJGRVl6WWt6d29hQXhCbWFjWVBEUnhYcldDSVI4Rm05RWtoQjJoc0g0RF85MkxpQ21CYWhyZG56RzF5eFRvbkl4emVTaUt3eGhqbS0xNmR5WkR0bmx2QkQ;
Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 14-Sep-2019 03:34:25
GMT; secure', 'session_tracker=k4wTKdlbdgmQMGGxHq.0.1505360065173.Z0FBQUFBQlp1ZmpCVXFIZFdVbjFFbEZibkRvV0pMOWlhZVV0M182dXUtUktVQkt0UnZFWXBkWm03TU1uRnRFQlEyLWFMdHEyWlhKX1ZCT2x2ZWR0bElTUnFIVXBkNVVWb01DS25Nc1dVcDhkamNQcGNXNjFLaUlxWU9aV2dhelRnUHNodk10eC1ldnk;
Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 14-Sep-2017 05:34:25
GMT; secure', edgebucket=pDW9Lys2h8bInGGb9N; Domain=reddit.com; Max-Age=63071999;
Path=/; secure]
Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload]
Vary: [accept-encoding]
Via: [1.1 varnish]
X-Cache: [MISS]
X-Cache-Hits: ['0']
X-Moose: [majestic]
X-Served-By: [cache-ord1731-ORD]
X-Timer: ['S1505360065.158056,VS0,VE145']
access-control-allow-origin: ['*']
access-control-expose-headers: ['X-Reddit-Tracking, X-Moose']
cache-control: ['max-age=0, must-revalidate']
set-cookie: ['loid=00000000000drcw01i.2.1505360065178.Z0FBQUFBQlp1ZmpCZnJBMlhNcFVMa0RON1lKNzlDUU5FelFZenQySllVckJKZlROOHZEbTJGRVl6WWt6d29hQXhCbWFjWVBEUnhYcldDSVI4Rm05RWtoQjJoc0g0RF85MkxpQ21CYWhyZG56RzF5eFRvbkl4emVTaUt3eGhqbS0xNmR5WkR0bmx2QkQ;
Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 14-Sep-2019 03:34:25
GMT; secure', 'session_tracker=k4wTKdlbdgmQMGGxHq.0.1505360065173.Z0FBQUFBQlp1ZmpCVXFIZFdVbjFFbEZibkRvV0pMOWlhZVV0M182dXUtUktVQkt0UnZFWXBkWm03TU1uRnRFQlEyLWFMdHEyWlhKX1ZCT2x2ZWR0bElTUnFIVXBkNVVWb01DS25Nc1dVcDhkamNQcGNXNjFLaUlxWU9aV2dhelRnUHNodk10eC1ldnk;
Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 14-Sep-2017 05:34:25
GMT; secure', edgebucket=pDW9Lys2h8bInGGb9N; Domain=reddit.com; Max-Age=63071999;
Path=/; secure]
x-content-type-options: [nosniff]
x-frame-options: [SAMEORIGIN]
x-reddit-tracking: ['https://pixel.redditmedia.com/pixel/of_destiny.png?v=w2zI10CKhN0cuDFpS5Sja3JHe8PHstPL2MPcD8GTAX7OzcKclWgtvdtPmP4khzGzFCgf3COGr7I%3D']
x-ua-compatible: [IE=edge]
x-xss-protection: [1; mode=block]
status: {code: 200, message: OK}
- request:
body: grant_type=refresh_token&redirect_uri=http%3A%2F%2F127.0.0.1%3A65000%2F&refresh_token=**********
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Authorization: ['**********']
Connection: [keep-alive]
Content-Length: ['122']
Content-Type: [application/x-www-form-urlencoded]
Cookie: [edgebucket=pDW9Lys2h8bInGGb9N; loid=00000000000drcw01i.2.1505360065178.Z0FBQUFBQlp1ZmpCZnJBMlhNcFVMa0RON1lKNzlDUU5FelFZenQySllVckJKZlROOHZEbTJGRVl6WWt6d29hQXhCbWFjWVBEUnhYcldDSVI4Rm05RWtoQjJoc0g0RF85MkxpQ21CYWhyZG56RzF5eFRvbkl4emVTaUt3eGhqbS0xNmR5WkR0bmx2QkQ;
session_tracker=k4wTKdlbdgmQMGGxHq.0.1505360065173.Z0FBQUFBQlp1ZmpCVXFIZFdVbjFFbEZibkRvV0pMOWlhZVV0M182dXUtUktVQkt0UnZFWXBkWm03TU1uRnRFQlEyLWFMdHEyWlhKX1ZCT2x2ZWR0bElTUnFIVXBkNVVWb01DS25Nc1dVcDhkamNQcGNXNjFLaUlxWU9aV2dhelRnUHNodk10eC1ldnk]
User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit']
method: POST
uri: https://api.reddit.com/api/v1/access_token/
response:
body: {string: '{"access_token": "j5nsE0MLZHcCWoY74w-qpiTinPs", "token_type":
"bearer", "device_id": "None", "expires_in": 3600, "scope": "edit history
identity mysubreddits privatemessages read report save submit subscribe vote"}'}
headers:
Accept-Ranges: [bytes]
Connection: [keep-alive]
Content-Length: ['214']
Content-Type: [application/json; charset=UTF-8]
Date: ['Thu, 14 Sep 2017 03:34:25 GMT']
Server: [snooserv]
Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload]
Via: [1.1 varnish]
X-Cache: [MISS]
X-Cache-Hits: ['0']
X-Moose: [majestic]
X-Served-By: [cache-ord1731-ORD]
X-Timer: ['S1505360065.422828,VS0,VE51']
cache-control: ['max-age=0, must-revalidate']
set-cookie: ['session_tracker=k4wTKdlbdgmQMGGxHq.0.1505360065436.Z0FBQUFBQlp1ZmpCdXVBRWRjeV9ZdzRHR08zenpXVWVkZFViN1F6dGdERDIycFVyZTJaX1pMcWxNeElxRXU1RHpYaVJ1aFR4bkVhM1NJWmVPMU5wcWYwRnl1THBwYTU2eGpzUU9LRmJjdy1aNHduaTFOY2JLazhGN1ExMkRnYzB1djd5cXRTTFllUnQ;
Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 14-Sep-2017 05:34:25
GMT; secure']
x-content-type-options: [nosniff]
x-frame-options: [SAMEORIGIN]
x-xss-protection: [1; mode=block]
status: {code: 200, message: OK}
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Authorization: ['**********']
Connection: [keep-alive]
User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit']
method: GET
uri: https://oauth.reddit.com/api/v1/me.json
response:
body:
string: !!binary |
H4sIAMH4uVkC/61W227cNhD9FWOfXdvS+rLJW5o6rdsiiIsWBVoUBCWNVsxSJMPLrneD/ntnKGpF
OdsmBfJirDW8nDlz5nA+LoRj0Bup9wCLl2ctlw7OzxYtcB8sOPz0ceGA27pjJlRS1Mxb3raijhG9
U2DxV1qywJ1bbgVXnj4q2LG0d0UheDJgRQ/KM9HggrIo/8bPdcdpubeBbm40U9rTLfVm+uo6vWO8
N0wKlX2WYgus48aAEmqNG3dTTKj3UHuGIOZQLUjYclXDM7QWeo2n1Vq50ENzEvDVkgDzxoHdgmUW
jLYeb55uXUdEzju2tngwEThihTWv9yMhxkKb5+HoGEbnihqYxVSDmeJ4I+PBawZPHhRBSYFeV0IC
20HFPLdrmINpoOVBeuasY52WjQ6U6RdwgSR4qyUrTrFQ3BUDCwewG3a6XgEzcSyllbED2mgTJLdM
qK8IqSyuCNKuEx7oUmiY6TPuhar0EwrYddM3PMFpxaU4cC+0ihXJtgSDBWxID3ojYiMcz/KAneFP
EV5b7ZzRGDRWt1iZKVRJXW8Y8cKqfVLOFD0WGEGEvMAaVbTG+yhOncqFzLD0VPgnvKvXrNcNlyPl
rMZWxeLg8j1rhOuFc6JCpQidbUcaucICwhZmUoWQ0mZG4zn7jBXfY6iPzFMrZptabVG5nfcmBzjo
UyHF2BcVV0OVxxIQU5h0IotV4PkUxaQb4QN6E7GD/wmLDZ1RE3ylkawh1yjAWTHIfqRer3GjYjWv
u0/TiWhPHJ2atOEo8MnvTpAexYCMe4HcJ2LcnGTDsegMU8g+WY3i6ntkpZ5HpgbJwJD3Ib54eoPS
nnvg5+Fgja2OfZK2DGqrSfbZNbUFUFuBrD3XAzE5KBa1xJHTvMA8Nf+MexeqoXzMBpl3TxKEA08y
zQLJTo6WysoshlC3wpN5Dv64s9jozxiKreUsaq3PQseOpCOjK2VlIPlBX0FuqBmbHKlG7dHOicLM
qvDhQj1jP56fdKrylFMVqztyqozRVuavFlZBS/lJBf5/o39S9Mx7Tfc1vbe8GZ6DweE8WuN/VM4C
HzHRLjJdfD+iA3CFC6etOJi44EyU/GKaTOKOWZuoICUxN0ou5hTVgEdE6KJCa6Wl4yECPzPRk2AH
D3h5eVld+C70lbsYTsERQPAL7KHLu1fSbO+t3vrH4vZKv3izf3hofnh9aH8uN9/A+/rFqvztNrx7
HQ4PFwabAM8fjO6LbzC/L399WG7l4XZTbx6+s++ul2/6n+T3fyxfPW31sj18+/a+qH80rn4cb8BS
G8n3Ue3x6RJPkaZFuKyR8elV6/gB2JK2dEg9tYg4UH8k1kaeIuKcZ6QTtSiqoWOKoSDjQEH8TZXa
wB55lpHhBd0U+zGmNy1qgI4zyXPisvHuPvjZ1XluMSX2mZQGnlNGGczn7w0aY3ySF/92XrCSwpeE
7CSPl1l1E5F/FuXq6vxsubr+C2MjZn/DlvLD3e0sT41g+aDEhEjTGFmssuTTlH2CLrJ9dAsuLAPF
scdzzqKiR0Tlze35Gf4hQJMT+70Z6EQ4dB4PjQBs9jTIPK/KJIAEl/qVvhuckGfdtEYvwcnUCBu5
ykoRFSk/KK6jLGI7O6JzWs2Cp7c17UA6RCtyQyanROJo8MFdaHokx7R6Ym/yDAKT8xJpn1Z0OEWN
lwzj1DyGi1n6Oh6hcTDryGePlre4L/W9/+WxbdpX7dvHqESBs2KL/sysrnQEOe6Pddtw21M3lOWK
UMV5tMbphWhH9Qy25rUZFhL5Q9WyNyDCm0OLu2K3OaX1lvtoiGN01OIpIRNmfPD50HnFdXlTLovb
66sLAhMLWk8A6FtanMoVN1yVq7QBB6w0u413j0PimPfqRcrgKKvjM/APhXUFzIQOAAA=
headers:
Accept-Ranges: [bytes]
Connection: [keep-alive]
Content-Encoding: [gzip]
Content-Length: ['1418']
Content-Type: [application/json; charset=UTF-8]
Date: ['Thu, 14 Sep 2017 03:34:25 GMT']
Server: [snooserv]
Set-Cookie: ['session_tracker=ccNg4m5YpT4IeulT85.0.1505360065667.Z0FBQUFBQlp1ZmpCaDZScFVxdENaeGdsdEg4azhBQ2pzaUVqQXhuOUFJcmw2Z3dBS09fN2ZlTHpkZTI3VDVtWEdnZmF5TmZHNDF5VV9SNFM3d1RsUmw3NVpnNUFTbjRDQ1NLbnpWRFRwOEZZMTZROVd5d09JdmpRV01zLW9aYlZ1YThYdDVtNjhPa3Y;
Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 14-Sep-2017 05:34:25
GMT; secure', edgebucket=iZJoZjF7XACk7ejFHw; Domain=reddit.com; Max-Age=63071999;
Path=/; secure]
Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload]
Vary: [accept-encoding]
Via: [1.1 varnish]
X-Cache: [MISS]
X-Cache-Hits: ['0']
X-Moose: [majestic]
X-Served-By: [cache-ord1747-ORD]
X-Timer: ['S1505360066.653595,VS0,VE60']
cache-control: ['private, s-maxage=0, max-age=0, must-revalidate, max-age=0,
must-revalidate']
expires: ['-1']
set-cookie: ['session_tracker=ccNg4m5YpT4IeulT85.0.1505360065667.Z0FBQUFBQlp1ZmpCaDZScFVxdENaeGdsdEg4azhBQ2pzaUVqQXhuOUFJcmw2Z3dBS09fN2ZlTHpkZTI3VDVtWEdnZmF5TmZHNDF5VV9SNFM3d1RsUmw3NVpnNUFTbjRDQ1NLbnpWRFRwOEZZMTZROVd5d09JdmpRV01zLW9aYlZ1YThYdDVtNjhPa3Y;
Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 14-Sep-2017 05:34:25
GMT; secure', edgebucket=iZJoZjF7XACk7ejFHw; Domain=reddit.com; Max-Age=63071999;
Path=/; secure]
x-content-type-options: [nosniff]
x-frame-options: [SAMEORIGIN]
x-ratelimit-remaining: ['592.0']
x-ratelimit-reset: ['335']
x-ratelimit-used: ['8']
x-xss-protection: [1; mode=block]
status: {code: 200, message: OK}
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Authorization: ['**********']
Connection: [keep-alive]
Cookie: [edgebucket=iZJoZjF7XACk7ejFHw; session_tracker=ccNg4m5YpT4IeulT85.0.1505360065667.Z0FBQUFBQlp1ZmpCaDZScFVxdENaeGdsdEg4azhBQ2pzaUVqQXhuOUFJcmw2Z3dBS09fN2ZlTHpkZTI3VDVtWEdnZmF5TmZHNDF5VV9SNFM3d1RsUmw3NVpnNUFTbjRDQ1NLbnpWRFRwOEZZMTZROVd5d09JdmpRV01zLW9aYlZ1YThYdDVtNjhPa3Y]
User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit']
method: GET
uri: https://oauth.reddit.com/r/python/.json
response:
body:
string: !!binary |
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
/wMQZadHQA0BAA==
headers:
Accept-Ranges: [bytes]
Connection: [keep-alive]
Content-Encoding: [gzip]
Content-Length: ['10726']
Content-Type: [application/json; charset=UTF-8]
Date: ['Thu, 14 Sep 2017 03:34:25 GMT']
Server: [snooserv]
Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload]
Vary: [accept-encoding]
Via: [1.1 varnish]
X-Cache: [MISS]
X-Cache-Hits: ['0']
X-Moose: [majestic]
X-Served-By: [cache-ord1747-ORD]
X-Timer: ['S1505360066.785562,VS0,VE153']
cache-control: ['private, s-maxage=0, max-age=0, must-revalidate, max-age=0,
must-revalidate']
expires: ['-1']
set-cookie: ['loid=0000000000000lqnao.2.1425202840186.Z0FBQUFBQlp1ZmpCQ2hwVmRON2pPcE4wQml3bHhrR3pnVGlkbjJDNldkVGhiMFc5c3loLXE3MERBTHV5eGQxWHg2ZkthNHhIN1MyZTFKUlU0eUVScTZVXzlyWkxwc0dQZGE1RGUwRk1uTnN6OThqSzZ5dXJHQ2dpcHpTc1RkSDhJeWs1WHBDZEFHeTY;
Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 14-Sep-2019 03:34:25
GMT; secure', 'session_tracker=ccNg4m5YpT4IeulT85.0.1505360065801.Z0FBQUFBQlp1ZmpCQmM0Q21zdlRWMTB0TmtqU25UOFdzcy10WkNybkc0YnRNelVjVFhWeEFaT05LU3RaWFBHUFAtNDVqRExKUW1kanJoRWNOYjRoSDRXS29IaXdfM1RZM1ZEX2t3X1doaWx3T2JHcVdzR1Z2N1o1X3VsUkFhNndtUk45Z2tjeWFQeXQ;
Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 14-Sep-2017 05:34:25
GMT; secure']
x-content-type-options: [nosniff]
x-frame-options: [SAMEORIGIN]
x-ratelimit-remaining: ['591.0']
x-ratelimit-reset: ['335']
x-ratelimit-used: ['9']
x-reddit-tracking: ['https://pixel.redditmedia.com/pixel/of_destiny.png?v=PCoJe8sg5slPNmRboPobsY1BcSSnQQTlQAJJgMBLg8KMtNFALTng99PGO0pHOcYtDa4hoNeeaElx5u5lqX5P7zuQLacty5Qb']
x-ua-compatible: [IE=edge]
x-xss-protection: [1; mode=block]
status: {code: 200, message: OK}
version: 1

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,8 @@ from vcr import VCR
from six.moves.urllib.parse import urlparse, parse_qs
from six.moves.BaseHTTPServer import HTTPServer
from rtv.oauth import OAuthHelper, OAuthHandler, OAuthRateLimiter
from rtv.oauth import OAuthHelper, OAuthHandler
from rtv.content import RequestHeaderRateLimiter
from rtv.config import Config
from rtv.packages import praw
from rtv.terminal import Terminal
@@ -180,8 +181,7 @@ def reddit(vcr, request):
with vcr.use_cassette(cassette_name):
with patch('rtv.packages.praw.Reddit.get_access_information'):
handler = OAuthRateLimiter()
handler = RequestHeaderRateLimiter()
reddit = praw.Reddit(user_agent='rtv test suite',
decode_html_entities=False,
disable_update_check=True,

View File

@@ -11,7 +11,8 @@ import pytest
from rtv import exceptions
from rtv.packages import praw
from rtv.content import (
Content, SubmissionContent, SubredditContent, SubscriptionContent)
Content, SubmissionContent, SubredditContent, SubscriptionContent,
RequestHeaderRateLimiter)
try:
from unittest import mock
@@ -560,3 +561,42 @@ def test_content_subscription_empty(reddit, terminal):
with terminal.loader():
SubscriptionContent.from_user(reddit, terminal.loader)
assert isinstance(terminal.loader.exception, exceptions.SubscriptionError)
def test_content_cache(reddit):
# Make sure the test suite is configured to use the custom handler
assert isinstance(reddit.handler, RequestHeaderRateLimiter)
assert not reddit.handler.cache
# A standard 200 response should be added to the cache
next(reddit.get_subreddit('python').get_hot())
request = list(reddit.handler.cache.values())[0]
assert request.url == 'https://api.reddit.com/r/python/.json'
# Clearing the cache should remove the request
reddit.handler.cache.clear()
assert not reddit.handler.cache
def test_content_rate_limit(reddit, oauth, refresh_token):
# Make sure the test suite is configured to use the custom handler
assert isinstance(reddit.handler, RequestHeaderRateLimiter)
assert not reddit.handler.cache
# unauthenticated requests don't return the x-ratelimit headers
# so they currently aren't limited
next(reddit.get_subreddit('python').get_hot())
assert reddit.handler.seconds_to_reset is None
oauth.config.refresh_token = refresh_token
oauth.authorize()
# But now that we're logged in the headers should be returned
next(reddit.get_subreddit('python').get_hot())
assert reddit.handler.seconds_to_reset
# Even though the headers were returned, the rate limiting should
# still not be triggering a delay for the next request
assert reddit.handler.next_request_timestamp is None

View File

@@ -7,7 +7,7 @@ import six
from rtv import __version__
from rtv.subreddit_page import SubredditPage
from rtv.packages.praw.errors import NotFound
from rtv.packages.praw.errors import NotFound, HTTPException
try:
from unittest import mock
@@ -66,6 +66,27 @@ def test_subreddit_refresh(subreddit_page, terminal):
assert terminal.loader.exception is None
def test_subreddit_reload_page(subreddit_page, terminal, reddit):
cache = reddit.handler.cache
assert len(cache) == 1
# A plain refresh_content() will use whatever is in the praw cache
# instead of making a new request to reddit
list(cache.values())[0].status_code = 503
subreddit_page.refresh_content()
assert isinstance(terminal.loader.exception, HTTPException)
cache = reddit.handler.cache
assert len(cache) == 1
# But if we manually trigger a page refresh, it should clear the cache
# and reload the page instead of returning the cached 503 response
list(cache.values())[0].status_code = 503
subreddit_page.controller.trigger('r')
assert terminal.loader.exception is None
def test_subreddit_title(subreddit_page, terminal, capsys):
subreddit_page.content.name = 'hello ❤'