Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# 0.5.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave 0.5.0 in place, and add 0.5.1 above it.

Here's an example: https://github.com/Patreon/patreon-js/blob/master/changelog.md

# 0.5.1
## Added
* Use six module to handle version compatibility
## Fixed
* Fixed the error that occured when calling extract_cursor in python2

# 0.5.0
* Make URL query param ordering consistent
* Use a first-party JSONAPIParser
* README improvements
* Update canonical API URL
* Set User-Agent for proper traffic attribution
* Make currently-unused parameter optional
* Improve flask example
* Thanks to: @21echoes, @tanabi, @phildini
* Thanks to: @21echoes, @tanabi, @phildini
5 changes: 3 additions & 2 deletions patreon/api.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import requests
import six

from patreon.jsonapi.parser import JSONAPIParser
from patreon.jsonapi.url_util import build_url
from patreon.schemas import campaign
from patreon.utils import user_agent_string
from patreon.version_compatibility.utc_timezone import utc_timezone
from patreon.version_compatibility.urllib_parse import urlencode, urlparse, parse_qs
from six.moves.urllib.parse import urlparse, parse_qs, urlencode


class API(object):
Expand Down Expand Up @@ -69,7 +70,7 @@ def head_and_tail(path):
if current_dict is None or (head is not None and tail is None):
return None
# Path stopped before leaf was reached
elif current_dict and type(current_dict) != str:
elif current_dict and type(current_dict) != six.text_type:
raise Exception(
'Provided cursor path did not result in a link', current_dict
)
Expand Down
52 changes: 27 additions & 25 deletions patreon/api_spec.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import datetime
import functools
import mock
import six

from patreon import api
from patreon.jsonapi import url_util
from patreon.jsonapi.parser import JSONAPIParser
from patreon.utils import user_agent_string
from patreon.version_compatibility import urllib_parse
from patreon.version_compatibility.utc_timezone import utc_timezone
from six.moves.urllib.parse import urlencode

MOCK_CAMPAIGN_ID = 12
API_ROOT_ENDPOINT = 'https://www.patreon.com/api/oauth2/api/'
MOCK_ACCESS_TOKEN = 'mock token'
MOCK_CURSOR_VALUE = 'Mock Cursor Value'
API_ROOT_ENDPOINT = 'https://www.patreon.com/api/oauth2/api/'
MOCK_ACCESS_TOKEN = 'mock token'
MOCK_CURSOR_VALUE = 'Mock Cursor Value'


DEFAULT_API_HEADERS = {
'Authorization': 'Bearer ' + MOCK_ACCESS_TOKEN,
Expand All @@ -35,7 +37,7 @@ def api_url(*segments, **query):
del query['includes']

if query:
path += '?' + urllib_parse.urlencode(query)
path += '?' + urlencode(query)

return url_util.build_url(
API_ROOT_ENDPOINT + path,
Expand Down Expand Up @@ -85,10 +87,10 @@ def execute_test(method_func, *args, **kwargs):
def test_extract_cursor_returns_cursor_when_provided():
assert MOCK_CURSOR_VALUE == api.API.extract_cursor(
{
'links':
six.text_type('links'):
{
'next':
'https://patreon.com/members?page[cursor]=' +
six.text_type('next'):
six.text_type('https://patreon.com/members?page[cursor]=') +
MOCK_CURSOR_VALUE,
},
}
Expand All @@ -98,17 +100,17 @@ def test_extract_cursor_returns_cursor_when_provided():
def test_extract_cursor_returns_None_when_no_cursor_provided():
assert None is api.API.extract_cursor(
{
'links': {
'next': 'https://patreon.com/members?page[offset]=25',
six.text_type('links'): {
six.text_type('next'): six.text_type('https://patreon.com/members?page[offset]=25'),
},
}
)


def test_extract_cursor_returns_None_when_link_is_not_a_string():
assert None is api.API.extract_cursor({
'links': {
'next': None,
'links': {
'next': None,
},
})

Expand All @@ -118,8 +120,8 @@ def test_extract_cursor_returns_None_when_link_is_malformed():

try:
api.API.extract_cursor({
'links': {
'next': 12,
'links': {
'next': 12,
},
})

Expand All @@ -132,12 +134,12 @@ def test_extract_cursor_returns_None_when_link_is_malformed():

@api_test()
def test_can_fetch_user():
return api_url('current_user'), client.fetch_user()
return api_url( 'current_user'), client.fetch_user()


@api_test()
def test_can_fetch_campaign():
expected_url = api_url('current_user', 'campaigns')
expected_url = api_url( 'current_user', 'campaigns')
response = client.fetch_campaign()
return expected_url, response

Expand All @@ -147,9 +149,9 @@ def test_can_fetch_api_and_patrons():
response = client.fetch_campaign_and_patrons()

expected_url = api_url(
'current_user',
'campaigns',
includes=['rewards', 'creator', 'goals', 'pledges'],
'current_user',
'campaigns',
includes=[ 'rewards', 'creator', 'goals', 'pledges'],
)

return expected_url, response
Expand All @@ -158,8 +160,8 @@ def test_can_fetch_api_and_patrons():
@api_test()
def test_can_fetch_api_and_patrons_with_custom_includes():
expected_url = api_url(
'current_user',
'campaigns',
'current_user',
'campaigns',
includes=['creator'],
)

Expand All @@ -179,7 +181,7 @@ def test_can_fetch_page_of_pledges():
query_params = {'page[count]': PAGE_COUNT}

expected_url = api_url(
'campaigns', MOCK_CAMPAIGN_ID, 'pledges', **query_params
'campaigns', MOCK_CAMPAIGN_ID, 'pledges', **query_params
)

return expected_url, response
Expand All @@ -202,7 +204,7 @@ def test_can_fetch_page_of_pledges_with_arbitrary_cursor():
}

expected_url = api_url(
'campaigns', MOCK_CAMPAIGN_ID, 'pledges', **query_params
'campaigns', MOCK_CAMPAIGN_ID, 'pledges', **query_params
)

return expected_url, response
Expand Down Expand Up @@ -233,7 +235,7 @@ def test_can_fetch_page_of_pledges_with_custom_options_without_tzinfo():
}

expected_url = api_url(
'campaigns', MOCK_CAMPAIGN_ID, 'pledges', **query_params
'campaigns', MOCK_CAMPAIGN_ID, 'pledges', **query_params
)

return expected_url, response
Expand Down Expand Up @@ -264,7 +266,7 @@ def test_can_fetch_page_of_pledges_with_custom_options_with_tzinfo():
}

expected_url = api_url(
'campaigns', MOCK_CAMPAIGN_ID, 'pledges', **query_params
'campaigns', MOCK_CAMPAIGN_ID, 'pledges', **query_params
)

return expected_url, response
3 changes: 1 addition & 2 deletions patreon/jsonapi/url_util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from collections import OrderedDict

from patreon.version_compatibility.urllib_parse import urlencode
from six.moves.urllib.parse import urlencode


def joined_or_null(arr):
Expand Down
7 changes: 0 additions & 7 deletions patreon/version_compatibility/urllib_parse.py

This file was deleted.

6 changes: 4 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def is_running_tests():

setup(
name='patreon',
version='0.5.0',
version='0.5.1',
description=DESCRIPTION,
url='http://github.com/Patreon/patreon-python',
author='Patreon',
Expand All @@ -29,6 +29,7 @@ def is_running_tests():
setup_requires=setup_requires,
install_requires=[
'requests',
'six>=1.10.0',
],
tests_require=[
'pytest',
Expand All @@ -37,7 +38,7 @@ def is_running_tests():
],
zip_safe=True,
classifiers=[
'Development Status :: 3 - Alpha',
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
Expand All @@ -50,5 +51,6 @@ def is_running_tests():
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
]
)