Skip to content

Commit

Permalink
Fixes #15 Refactored common rest API calls into helper class
Browse files Browse the repository at this point in the history
  • Loading branch information
TheFriendlyCoder committed Apr 16, 2018
1 parent ad685c1 commit 049a456
Show file tree
Hide file tree
Showing 18 changed files with 249 additions and 220 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -22,4 +22,5 @@ venv*/
**/*.orig

# project files
.vscode/
.vscode/
.idea/
5 changes: 5 additions & 0 deletions .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions docs/friendlypins.utils.rest_io.rst
@@ -0,0 +1,7 @@
friendlypins.utils.rest\_io module
==================================

.. automodule:: friendlypins.utils.rest_io
:members:
:undoc-members:
:show-inheritance:
1 change: 1 addition & 0 deletions docs/friendlypins.utils.rst
Expand Up @@ -7,6 +7,7 @@ Submodules
.. toctree::

friendlypins.utils.console_actions
friendlypins.utils.rest_io

Module contents
---------------
Expand Down
29 changes: 8 additions & 21 deletions src/friendlypins/api.py
@@ -1,9 +1,9 @@
"""Primary entry point for the Friendly Pinterest library"""
from __future__ import print_function
import logging
import requests
from friendlypins.user import User
from friendlypins.headers import Headers
from friendlypins.utils.rest_io import RestIO


class API(object): # pylint: disable=too-few-public-methods
"""High level abstraction for the core Pinterest API
Expand All @@ -13,15 +13,12 @@ class API(object): # pylint: disable=too-few-public-methods
Pinterest data
"""

# URL of the root namespace for the Pinterest API
_root_url = 'https://api.pinterest.com/v1'

def __init__(self, personal_access_token):
self._log = logging.getLogger(__name__)
self._token = personal_access_token
self._io = RestIO(personal_access_token)

def get_user(self, username=None):
"""Gets all primitives associated with a particular Pinterst user
"""Gets all primitives associated with a particular Pinterest user
:param str username:
Optional name of a user to look up
Expand All @@ -34,23 +31,13 @@ def get_user(self, username=None):
if username:
raise NotImplementedError(
"Querying arbitrary Pinerest users is not yet supported.")
else:
temp_url = "{0}/me".format(self._root_url)
temp_url += "?access_token={0}".format(self._token)
temp_url += "&fields=id,username,first_name,last_name,bio,created_at,counts,image"
response = requests.get(temp_url)
response.raise_for_status()

header = Headers(response.headers)
self._log.debug("Getting user query response: %s", header)

raw = response.json()

assert 'data' in raw
fields = "id,username,first_name,last_name,bio,created_at,counts,image"
result = self._io.get("me", {"fields": fields})
assert 'data' in result

return User(raw['data'], self._root_url, self._token)
return User(result['data'], self._io)


# pylint: disable-all
if __name__ == "__main__":
pass
66 changes: 33 additions & 33 deletions src/friendlypins/board.py
@@ -1,24 +1,21 @@
"""Primitives for interacting with Pinterest boards"""
import logging
import json
import requests
from friendlypins.headers import Headers
from friendlypins.pin import Pin


class Board(object):
"""Abstraction around a Pinterest board
:param dict data: Raw Pinterest API data describing the board
:param str root_url: URL of the Pinterest REST API
:param str token: Authentication token for the REST API
:param rest_io: reference to the Pinterest REST API
:type rest_io: :class:`friendlypins.utils.rest_io.RestIO`
"""

def __init__(self, data, root_url, token):
def __init__(self, data, rest_io):
self._log = logging.getLogger(__name__)
self._data = data
self._root_url = root_url
self._token = token
self._io = rest_io

def __str__(self):
"""String representation of this board, for debugging purposes
Expand Down Expand Up @@ -76,37 +73,40 @@ def all_pins(self):
:rtype: :class:`list` of :class:`friendlypins.pin.Pin`
"""
self._log.debug('Gettings all pins for board %s...', self.name)

temp_url = '{0}/boards/{1}/pins/'.format(self._root_url, self.unique_id)
temp_url += "?access_token={0}".format(self._token)
temp_url += "&limit=100"
temp_url += "&fields=id,link,url,creator,board,created_at,note,color"
temp_url += ",counts,media,attribution,image,metadata,original_link"
response = requests.get(temp_url)
response.raise_for_status()
retval = []
header = Headers(response.headers)
self._log.debug("Pins query response header %s", header)
retval = list()

properties = {
"fields": ','.join([
"id",
"link",
"url",
"creator",
"board",
"created_at",
"note,color",
"counts",
"media",
"attribution",
"image",
"metadata",
"original_link"
])
}

while True:
raw = response.json()
assert 'data' in raw

for cur_item in raw['data']:
retval.append(Pin(cur_item, self._root_url, self._token))

self._log.debug("Raw keys are %s", raw.keys())
self._log.debug("Paged info is %s", raw['page'])
if not raw['page']['cursor']:
result = self._io.get(
"boards/{0}/pins".format(self.unique_id),
properties)
assert 'data' in result

for cur_item in result['data']:
retval.append(Pin(cur_item, self._io))
if not result["page"]["cursor"]:
break

paged_url = temp_url + "&cursor={0}".format(raw['page']['cursor'])
response = requests.get(paged_url)
response.raise_for_status()
header = Headers(response.headers)
self._log.debug("Pins query response header %s", header)
properties["cursor"] = result["page"]["cursor"]

return retval


if __name__ == "__main__":
pass
2 changes: 2 additions & 0 deletions src/friendlypins/headers.py
Expand Up @@ -3,6 +3,7 @@
import json
from dateutil import tz


class Headers(object):
"""Abstraction around the Pinterest API HTTP response header
Expand Down Expand Up @@ -87,5 +88,6 @@ def bytes(self):
"""
return int(self._data['Content-Length'])


if __name__ == "__main__":
pass
22 changes: 5 additions & 17 deletions src/friendlypins/pin.py
@@ -1,23 +1,20 @@
"""Primitives for operating on Pinterest pins"""
import logging
import json
import requests
from friendlypins.headers import Headers
from friendlypins.thumbnail import Thumbnail


class Pin(object):
"""Abstraction around a Pinterest pin
:param dict data: Raw Pinterest API data describing a pin
:param str root_url: URL of the Pinterest REST API
:param str token: Authentication token for interacting with the API
:param rest_io: reference to the Pinterest REST API
:type rest_io: :class:`friendlypins.utils.rest_io.RestIO`
"""

def __init__(self, data, root_url, token):
def __init__(self, data, rest_io):
self._log = logging.getLogger(__name__)
self._root_url = root_url
self._token = token
self._io = rest_io
self._data = data

def __str__(self):
Expand Down Expand Up @@ -92,17 +89,8 @@ def thumbnail(self):
def delete(self):
"""Removes this pin from it's respective board"""
self._log.debug('Deleting pin %s', repr(self))
temp_url = '{0}/pins/{1}/'.format(
self._root_url,
self.unique_id)
temp_url += "?access_token={0}".format(self._token)
self._io.delete('pins/{0}'.format(self.unique_id))

response = requests.delete(temp_url)

header = Headers(response.headers)
self._log.debug("Boards query response header %s", header)

response.raise_for_status()

if __name__ == "__main__":
pass
2 changes: 2 additions & 0 deletions src/friendlypins/scripts/fpins.py
Expand Up @@ -5,6 +5,7 @@
import sys
from friendlypins.utils.console_actions import download_thumbnails


def _download_thumbnails(args):
"""Callback for performing the thumbnail download operation
Expand Down Expand Up @@ -141,5 +142,6 @@ def main(args=None):
log.debug("Details: ", exc_info=True)
return -1


if __name__ == "__main__":
pass
1 change: 1 addition & 0 deletions src/friendlypins/thumbnail.py
Expand Up @@ -56,5 +56,6 @@ def url(self):
"""
return self._data['original']['url']


if __name__ == "__main__":
pass
29 changes: 10 additions & 19 deletions src/friendlypins/user.py
@@ -1,24 +1,21 @@
"""Interfaces for interacting with Pinterest users"""
import logging
import json
import requests
from friendlypins.board import Board
from friendlypins.headers import Headers


class User(object):
"""Abstraction around a Pinterest user and their associated data
:param dict data: JSON data parsed from the API
:param str root_url: URL of the Pinterest REST API
:param str token: Authentication token for interacting with the API
:param rest_io: reference to the Pinterest REST API
:type rest_io: :class:`friendlypins.utils.rest_io.RestIO`
"""

def __init__(self, data, root_url, token):
def __init__(self, data, rest_io):
self._log = logging.getLogger(__name__)
self._data = data
self._root_url = root_url
self._token = token
self._io = rest_io

def __str__(self):
"""String representation of this user, for debugging purposes
Expand Down Expand Up @@ -103,22 +100,16 @@ def boards(self):
"""
self._log.debug("Loading boards for user %s...", self.name)

temp_url = '{0}/me/boards/'.format(self._root_url)
temp_url += "?access_token={0}".format(self._token)
temp_url += "&fields=id,name,url,description,creator,created_at,counts,image"
response = requests.get(temp_url)
fields = "id,name,url,description,creator,created_at,counts,image"
result = self._io.get('me/boards', {"fields": fields})

header = Headers(response.headers)
self._log.debug("Boards query response header %s", header)

response.raise_for_status()
raw = response.json()
assert 'data' in raw
assert 'data' in result

retval = []
for cur_item in raw['data']:
retval.append(Board(cur_item, self._root_url, self._token))
for cur_item in result['data']:
retval.append(Board(cur_item, self._io))
return retval


if __name__ == "__main__":
pass
3 changes: 3 additions & 0 deletions src/friendlypins/utils/console_actions.py
Expand Up @@ -7,6 +7,7 @@
from friendlypins.api import API
from friendlypins.headers import Headers


def _download_pin(pin, folder):
"""Helper method for downloading a thumbnail from a single pin
Expand Down Expand Up @@ -44,6 +45,7 @@ def _download_pin(pin, folder):
return 2
return 0


def download_thumbnails(api_token, board_name, output_folder, delete):
"""Downloads thumbnails of all pins on a board
Expand Down Expand Up @@ -85,5 +87,6 @@ def download_thumbnails(api_token, board_name, output_folder, delete):

return 0


if __name__ == "__main__":
pass

0 comments on commit 049a456

Please sign in to comment.