Skip to content

Commit

Permalink
Merge pull request #9 from praw-dev/reformat
Browse files Browse the repository at this point in the history
Reformat lines to 88 and enforce f-strings
  • Loading branch information
LilSpazJoekp authored Sep 28, 2020
2 parents 62ad1c9 + e61937b commit f8763b4
Show file tree
Hide file tree
Showing 24 changed files with 174 additions and 315 deletions.
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[flake8]
ignore = E203 E501 W503 W504
exclude = .eggs,docs,.venv
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install .[lint]
- name: Run flynt
run: flynt -vdf -tc -ll 1000 .
- name: Run black
run: black --check --verbose .
- name: Run flake8
Expand Down
9 changes: 5 additions & 4 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
Change Log
==========

asyncprawcore follows `semantic versioning <http://semver.org/>`_ with the
exception that deprecations will not be announced by a minor release.
asyncprawcore follows `semantic versioning <http://semver.org/>`_ with the exception
that deprecations will not be announced by a minor release.

1.4.0.post2 (2020-07-12)
------------------------

**Fixed**

* How files are handled. ``data`` is now able to be passed with ``files`` since
asyncpraw can make requests with both parameters.
* Fixed ``SpecialException`` not able to get ``response.json()`` since it is a coroutine.
asyncpraw can make requests with both parameters.
* Fixed ``SpecialException`` not able to get ``response.json()`` since it is a
coroutine.

1.4.0.post1 (2020-07-03)
------------------------
Expand Down
37 changes: 11 additions & 26 deletions asyncprawcore/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ def authorize_url(self, duration, scopes, state, implicit=False):
)
if implicit and duration != "temporary":
raise InvalidInvocation(
"The implicit grant flow only supports "
"temporary access tokens."
"The implicit grant flow only supports " "temporary access tokens."
)

params = {
Expand Down Expand Up @@ -115,9 +114,7 @@ def __init__(self, requestor, client_id, client_secret, redirect_uri=None):
``authorize`` method of the ``Authorizer`` class.
"""
super(TrustedAuthenticator, self).__init__(
requestor, client_id, redirect_uri
)
super(TrustedAuthenticator, self).__init__(requestor, client_id, redirect_uri)
self.client_secret = client_secret

def _auth(self):
Expand Down Expand Up @@ -150,9 +147,7 @@ def _clear_access_token(self):
self.scopes = None

async def _request_token(self, **data):
url = (
self._authenticator._requestor.reddit_url + const.ACCESS_TOKEN_PATH
)
url = self._authenticator._requestor.reddit_url + const.ACCESS_TOKEN_PATH
pre_request_time = time.time()
response = await self._authenticator._post(url, **data)
payload = await response.json()
Expand All @@ -161,9 +156,7 @@ async def _request_token(self, **data):
response, payload["error"], payload.get("error_description")
)

self._expiration_timestamp = (
pre_request_time - 10 + payload["expires_in"]
)
self._expiration_timestamp = pre_request_time - 10 + payload["expires_in"]
self.access_token = payload["access_token"]
if "refresh_token" in payload:
self.refresh_token = payload["refresh_token"]
Expand All @@ -183,18 +176,15 @@ def is_valid(self):
"""
return (
self.access_token is not None
and time.time() < self._expiration_timestamp
self.access_token is not None and time.time() < self._expiration_timestamp
)

async def revoke(self):
"""Revoke the current Authorization."""
if self.access_token is None:
raise InvalidInvocation("no token available to revoke")

await self._authenticator.revoke_token(
self.access_token, "access_token"
)
await self._authenticator.revoke_token(self.access_token, "access_token")
self._clear_access_token()


Expand Down Expand Up @@ -251,9 +241,7 @@ async def revoke(self, only_access=False):
if only_access or self.refresh_token is None:
await super(Authorizer, self).revoke()
else:
await self._authenticator.revoke_token(
self.refresh_token, "refresh_token"
)
await self._authenticator.revoke_token(self.refresh_token, "refresh_token")
self._clear_access_token()
self.refresh_token = None

Expand Down Expand Up @@ -283,9 +271,7 @@ def __init__(self, authenticator, device_id="DO_NOT_TRACK_THIS_DEVICE"):
async def refresh(self):
"""Obtain a new access token."""
grant_type = "https://oauth.reddit.com/grants/installed_client"
await self._request_token(
grant_type=grant_type, device_id=self._device_id
)
await self._request_token(grant_type=grant_type, device_id=self._device_id)


class ImplicitAuthorizer(BaseAuthorizer):
Expand Down Expand Up @@ -334,8 +320,8 @@ async def refresh(self):
class ScriptAuthorizer(Authorizer):
"""Manages personal-use script type authorizations.
Only users who are listed as developers for the application will be
granted access tokens.
Only users who are listed as developers for the application will be granted access
tokens.
"""

Expand All @@ -345,8 +331,7 @@ def __init__(self, authenticator, username, password):
"""Represent a single personal-use authorization to Reddit's API.
:param authenticator: An instance of :class:`TrustedAuthenticator`.
:param username: The Reddit username of one of the application's
developers.
:param username: The Reddit username of one of the application's developers.
:param password: The password associated with ``username``.
"""
Expand Down
12 changes: 2 additions & 10 deletions asyncprawcore/codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ def _make_into_dict(tupledict):
404: ("not_found", "-o-"),
405: ("method_not_allowed", "not_allowed"),
406: ("not_acceptable",),
407: (
"proxy_authentication_required",
"proxy_auth",
"proxy_authentication",
),
407: ("proxy_authentication_required", "proxy_auth", "proxy_authentication"),
408: ("request_timeout", "timeout"),
409: ("conflict",),
410: ("gone",),
Expand Down Expand Up @@ -94,11 +90,7 @@ def _make_into_dict(tupledict):
507: ("insufficient_storage",),
509: ("bandwidth_limit_exceeded", "bandwidth"),
510: ("not_extended",),
511: (
"network_authentication_required",
"network_auth",
"network_authentication",
),
511: ("network_authentication_required", "network_auth", "network_authentication"),
}

codes = _make_into_dict(_codes)
4 changes: 1 addition & 3 deletions asyncprawcore/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,7 @@ def __init__(self, response, resp_dict):
self.message = resp_dict.get("message", "")
self.reason = resp_dict.get("reason", "")
self.special_errors = resp_dict.get("special_errors", [])
AsyncPrawcoreException.__init__(
self, f"Special error {self.message!r}"
)
AsyncPrawcoreException.__init__(self, f"Special error {self.message!r}")


class TooLarge(ResponseException):
Expand Down
18 changes: 7 additions & 11 deletions asyncprawcore/rate_limit.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,12 @@ def __init__(self):
self.reset_timestamp = None
self.used = None

async def call(
self, request_function, set_header_callback, *args, **kwargs
):
async def call(self, request_function, set_header_callback, *args, **kwargs):
"""Rate limit the call to request_function.
:param request_function: A function call that returns an HTTP response
object.
:param set_header_callback: A callback function used to set the request
headers. This callback is called after any necessary sleep time
occurs.
:param request_function: A function call that returns an HTTP response object.
:param set_header_callback: A callback function used to set the request headers.
This callback is called after any necessary sleep time occurs.
:param *args: The positional arguments to ``request_function``.
:param **kwargs: The keyword arguments to ``request_function``.
Expand All @@ -56,9 +52,9 @@ def update(self, response_headers):
This method should only be called following a HTTP request to reddit.
Response headers that do not contain x-ratelimit fields will be treated
as a single request. This behavior is to error on the safe-side as such
responses should trigger exceptions that indicate invalid behavior.
Response headers that do not contain x-ratelimit fields will be treated as a
single request. This behavior is to error on the safe-side as such responses
should trigger exceptions that indicate invalid behavior.
"""
if "x-ratelimit-remaining" not in response_headers:
Expand Down
18 changes: 9 additions & 9 deletions asyncprawcore/requestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ def __init__(
):
"""Create an instance of the Requestor class.
:param user_agent: The user-agent for your application. Please follow
reddit's user-agent guidlines:
https://github.com/reddit/reddit/wiki/API#rules
:param oauth_url: (Optional) The URL used to make OAuth requests to the
reddit site. (Default: https://oauth.reddit.com)
:param reddit_url: (Optional) The URL used when obtaining access
tokens. (Default: https://www.reddit.com)
:param session: (Optional) A session to handle requests, compatible
with aiohttp.ClientSession(). (Default: None)
:param user_agent: The user-agent for your application. Please follow reddit's
user-agent guidlines: https://github.com/reddit/reddit/wiki/API#rules
:param oauth_url: (Optional) The URL used to make OAuth requests to the reddit
site. (Default: https://oauth.reddit.com)
:param reddit_url: (Optional) The URL used when obtaining access tokens.
(Default: https://www.reddit.com)
:param session: (Optional) A session to handle requests, compatible with
aiohttp.ClientSession(). (Default: None)
"""
if user_agent is None or len(user_agent) < 7:
raise InvalidInvocation("user_agent is not descriptive")
Expand Down
55 changes: 33 additions & 22 deletions asyncprawcore/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,14 @@ async def _do_retry(
)

async def _make_request(
self, data, json, method, params, retry_strategy_state, timeout, url,
self,
data,
json,
method,
params,
retry_strategy_state,
timeout,
url,
):
try:
response = await self._rate_limiter.call(
Expand All @@ -190,8 +197,11 @@ async def _make_request(
)
return response, None
except RequestException as exception:
if not retry_strategy_state.should_retry_on_failure() or not isinstance( # noqa: E501
exception.original_exception, self.RETRY_EXCEPTIONS
if (
not retry_strategy_state.should_retry_on_failure()
or not isinstance( # noqa: E501
exception.original_exception, self.RETRY_EXCEPTIONS
)
):
raise
return None, exception.original_exception
Expand All @@ -210,7 +220,13 @@ async def _request_with_retries(
retry_strategy_state = self._retry_strategy_class()
self._log_request(data, method, params, url)
response, saved_exception = await self._make_request(
data, json, method, params, retry_strategy_state, timeout, url,
data,
json,
method,
params,
retry_strategy_state,
timeout,
url,
)

do_retry = False
Expand All @@ -220,9 +236,7 @@ async def _request_with_retries(
do_retry = True

if retry_strategy_state.should_retry_on_failure() and (
do_retry
or response is None
or response.status in self.RETRY_STATUSES
do_retry or response is None or response.status in self.RETRY_STATUSES
):
return await self._do_retry(
data,
Expand Down Expand Up @@ -257,9 +271,7 @@ async def _request_with_retries(
raise BadJSON(response)

async def _set_header_callback(self):
if not self._authorizer.is_valid() and hasattr(
self._authorizer, "refresh"
):
if not self._authorizer.is_valid() and hasattr(self._authorizer, "refresh"):
await self._authorizer.refresh()
return {"Authorization": f"bearer {self._authorizer.access_token}"}

Expand All @@ -284,18 +296,17 @@ async def request(
"""Return the json content from the resource at ``path``.
:param method: The request verb. E.g., get, post, put.
:param path: The path of the request. This path will be combined with
the ``oauth_url`` of the Requestor.
:param data: Dictionary, bytes, or file-like object to send in the body
of the request.
:param files: Dictionary, mapping ``filename`` to file-like object.
:param json: Object to be serialized to JSON in the body of the
:param path: The path of the request. This path will be combined with the
``oauth_url`` of the Requestor.
:param data: Dictionary, bytes, or file-like object to send in the body of the
request.
:param files: Dictionary, mapping ``filename`` to file-like object.
:param json: Object to be serialized to JSON in the body of the request.
:param params: The query parameters to send with the request.
Automatically refreshes the access token if it becomes invalid and a
refresh token is available. Raises InvalidInvocation in such a case if
a refresh token is not available.
Automatically refreshes the access token if it becomes invalid and a refresh
token is available. Raises InvalidInvocation in such a case if a refresh token
is not available.
"""
params = deepcopy(params) or {}
Expand All @@ -318,9 +329,9 @@ async def request(
def validate_data_files(data, files):
"""Transfers the files and data from the arguments into the data.
This is done to maintain consistency with prawcore
:param data dictionary of data
:param files dictionary of "file" mapped to file-stream
This is done to maintain consistency with prawcore :param data dictionary of
data :param files dictionary of "file" mapped to file-stream
"""
if isinstance(data, dict):
data = deepcopy(data)
Expand Down
19 changes: 7 additions & 12 deletions examples/caching_requestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

"""This example shows how simple in-memory caching can be used.
Demonstrates the use of custom sessions with ``Requestor``. It's an adaptation
of ``read_only_auth_trophies.py``.
Demonstrates the use of custom sessions with ``Requestor``. It's an adaptation of
``read_only_auth_trophies.py``.
"""

Expand All @@ -19,6 +19,7 @@ class CachingSession(aiohttp.ClientSession):
Toy example of custom session to showcase the ``session`` parameter of
``Requestor``.
"""

get_cache = {}
Expand Down Expand Up @@ -58,29 +59,23 @@ async def main():
user = sys.argv[1]

async with asyncprawcore.session(authorizer) as session:
data1 = await session.request(
"GET", f"/api/v1/user/{user}/trophies"
)
data1 = await session.request("GET", f"/api/v1/user/{user}/trophies")

async with asyncprawcore.session(authorizer) as session:
data2 = await session.request(
"GET", f"/api/v1/user/{user}/trophies"
)
data2 = await session.request("GET", f"/api/v1/user/{user}/trophies")

for trophy in data1["data"]["trophies"]:
description = trophy["data"]["description"]
print(
"Original:",
trophy["data"]["name"]
+ (f" ({description})" if description else ""),
trophy["data"]["name"] + (f" ({description})" if description else ""),
)

for trophy in data2["data"]["trophies"]:
description = trophy["data"]["description"]
print(
"Cached:",
trophy["data"]["name"]
+ (f" ({description})" if description else ""),
trophy["data"]["name"] + (f" ({description})" if description else ""),
)
print(
"----\nCached == Original:",
Expand Down
Loading

0 comments on commit f8763b4

Please sign in to comment.