Skip to content

Commit

Permalink
Switch marvelous to python3, revamp caching approach to be more flexi…
Browse files Browse the repository at this point in the history
…ble.
  • Loading branch information
rkuykendall committed Nov 6, 2016
1 parent 6729cc5 commit 2ae86ca
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 76 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
*.sqlite
*.db

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
63 changes: 45 additions & 18 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ marvelous
=========

Marvel API python wrapper.
[Read the project documentation](http://marvelous.readthedocs.org/en/latest/)

Contributing
------------
Expand Down Expand Up @@ -41,23 +42,49 @@ complete Marvel pull list, excluding any series the user doesn't want.
'format': "comic",
'formatType': "comic",
'noVariants': True,
'dateDescriptor': "thisWeek"}),
'dateDescriptor': "thisWeek",
'limit': 100}),
key=lambda comic: comic.title)
# Grab the sale date of any of the comics for the folder name
directory = pulls[0].dates.on_sale.strftime('%m-%d')
# If there's no folder by that name, create one
if not os.path.exists(directory):
os.makedirs(directory)
# Create a pulls.txt file in that folder
with open(directory + '/pulls.txt', 'w') as pull_checklist:
# Check each comic that came out this week
for comic in pulls:
# If this series isn't in my ignore list
if comic.series.id not in IGNORE:
# Write a line to the file with the name of the issue, and the
# id of the series incase I want to add it to my ignore list
pull_checklist.write('{} (series #{})\n'.format(
comic.title.encode('utf-8'), comic.series.id))
# Grab the sale date of any of the comics for the current week
week = pulls[0].dates.on_sale.strftime('%m/%d')
print("New comics for the week of {}:".format(week))
# Check each comic that came out this week
for comic in pulls:
# If this series isn't in my ignore list
if comic.series.id not in IGNORE:
# Write a line to the file with the name of the issue, and the
# id of the series incase I want to add it to my ignore list
print('- {} (series #{})'.format(comic.title, comic.series.id))
Example output::

New comics for the week of 11/09:
- All-New X-Men (2015) #15 (series #20622)
- Amazing Spider-Man: Renew Your Vows (2016) #1 (series #22545)
- Black Panther: World of Wakanda (2016) #1 (series #22549)
- Captain America: Steve Rogers (2016) #7 (series #21098)
- Daredevil (2015) #13 (series #20780)
- Dark Tower: The Drawing of the Three - The Sailor (2016) #2 (series #19377)
- Deadpool: Back in Black (2016) #3 (series #21489)
- Doctor Strange And The Sorcerers Supreme (2016) #2 (series #22560)
- Gwenpool (2016) #8 (series #21490)
- Han Solo (2016) #5 (series #19711)
- Invincible Iron Man (2016) #1 (series #22928)
- Max Ride: Final Flight (2016) #3 (series #22197)
- Mosaic (2016) #2 (series #20818)
- Ms. Marvel (2015) #13 (series #20615)
- Old Man Logan (2016) #13 (series #20617)
- Power Man and Iron Fist (2016) #10 (series #21122)
- Prowler (2016) #2 (series #22535)
- Solo (2016) #2 (series #22441)
- Spider-Gwen (2015) #14 (series #20505)
- Spider-Man/Deadpool (2016) #11 (series #19679)
- Star Wars: The Force Awakens Adaptation (2016) #6 (series #21493)
- The Avengers (2016) #1.1 (series #22966)
- The Clone Conspiracy (2016) #2 (series #22654)
- Thunderbolts (2016) #7 (series #20884)
- Uncanny Avengers (2015) #16 (series #20621)
- Uncanny X-Men (2016) #15 (series #20612)
35 changes: 6 additions & 29 deletions marvelous/__init__.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,12 @@
from session import Session
from exceptions import AuthenticationError, LibraryError
from . import session, exceptions
from .sqlite_cache import SqliteCache


def api(public_key=None, private_key=None, cache=False):
def api(public_key=None, private_key=None, cache=None):
if public_key is None:
raise AuthenticationError("Missing public_key.")
raise exceptions.AuthenticationError("Missing public_key.")

if private_key is None:
raise AuthenticationError("Missing private_key.")
raise exceptions.AuthenticationError("Missing private_key.")

if cache:
try:
from requests_cache import CachedSession

cache_defaults = {
'backend': 'sqlite',
'expire_after': 60*60*24, # 24 hours
'ignored_parameters': ['hash', 'ts', 'apikey']
}

# Override the name and kwargs of the cache by passing a dict into
# the cache kwarg
if isinstance(cache, dict):
cache_defaults.update(cache)

cache = CachedSession(
cache_defaults.get('name', 'marvelous'), **cache_defaults)
except:
raise LibraryError(
"Marvelous only supports cache with requests-cache >= 0.4.11, "
"not yet on pypi. To install the newest requests-cache, run "
"`pip install requests-cache`.")

return Session(public_key, private_key, cached_requests=cache)
return session.Session(public_key, private_key, cache=cache)
10 changes: 5 additions & 5 deletions marvelous/comic.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from marshmallow import Schema, fields, pre_load, post_load
from dates import DatesSchema
from series import SeriesSchema

from . import dates, series


class Comic():
def __init__(self, **kwargs):
for k, v in kwargs.iteritems():
for k, v in kwargs.items():
setattr(self, k, v)


Expand All @@ -27,11 +27,11 @@ class ComicSchema(Schema):
# textObjects
# resourceURI
# urls
series = fields.Nested(SeriesSchema)
series = fields.Nested(series.SeriesSchema)
# variants
# collections
# collectedIssues
dates = fields.Nested(DatesSchema)
dates = fields.Nested(dates.DatesSchema)
# prices
# thumbnail
# images
Expand Down
3 changes: 1 addition & 2 deletions marvelous/comics_list.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import itertools

import comic
import exceptions
from . import comic, exceptions


class ComicsList():
Expand Down
4 changes: 2 additions & 2 deletions marvelous/series.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from marshmallow import Schema, fields, pre_load, post_load

import comics_list
from . import comics_list


class Series():
def __init__(self, **kwargs):
if 'response' not in kwargs:
kwargs['response'] = None

for k, v in kwargs.iteritems():
for k, v in kwargs.items():
setattr(self, k, v)

def comics(self, params):
Expand Down
37 changes: 20 additions & 17 deletions marvelous/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,57 @@
import hashlib
import requests

import exceptions
import comics_list
import series
from . import exceptions, comics_list, series


class Session():
api_url = "http://gateway.marvel.com:80/v1/public/{}"

def __init__(
self, public_key, private_key, cached_requests=None,
self, public_key, private_key, cache=None,
print_calls=False):

self.public_key = public_key
self.private_key = private_key
self.print_calls = print_calls

if cached_requests:
self.requests = cached_requests
else:
self.requests = requests
self.cache = cache

def call(self, endpoint, params=None):
if params is None:
params = {}

now_string = datetime.datetime.now().strftime('%Y-%m-%d%H:%M:%S')
auth_hash = hashlib.md5()
auth_hash.update(now_string)
auth_hash.update(self.private_key)
auth_hash.update(self.public_key)
auth_hash.update(now_string.encode('utf-8'))
auth_hash.update(self.private_key.encode('utf-8'))
auth_hash.update(self.public_key.encode('utf-8'))

params['hash'] = auth_hash.hexdigest()
params['apikey'] = self.public_key
params['ts'] = now_string

url = self.api_url.format('/'.join([str(e) for e in endpoint]))

response = self.requests.get(url, params=params)
if self.cache:
cached_response = self.cache.get(url)

if cached_response:
return cached_response

response = requests.get(url, params=params)

if self.print_calls:
print response.url
print(response.url)

response = response.json()
data = response.json()

if 'message' in response:
if 'message' in data:
raise exceptions.ApiError(response['message'])

return response
if self.cache and response.status_code == 200:
self.cache.store(url, data)

return data

def comics(self, params=None):
if params is None:
Expand Down
24 changes: 24 additions & 0 deletions marvelous/sqlite_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import json
import sqlite3


class SqliteCache:
def __init__(self, db_name="marvelous_cache.db"):
self.con = sqlite3.connect(db_name)
self.cur = self.con.cursor()
self.cur.execute("CREATE TABLE IF NOT EXISTS responses (key, json)")

def get(self, key):
self.cur.execute("SELECT json FROM responses WHERE key = ?", (key,))
result = self.cur.fetchone()

if result:
return json.loads(result[0])

return None

def store(self, key, value):
self.cur.execute(
"INSERT INTO responses(key, json) VALUES(?, ?)",
(key, json.dumps(value)))
self.con.commit()
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
marshmallow==2.6.0
nose==1.3.7
requests==2.9.1
requests-cache==0.4.12
sphinx-rtd-theme==0.1.9
4 changes: 2 additions & 2 deletions tests/comic_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ def setUp(self):
pub = os.getenv('PUBLIC_KEY', 'pub')
priv = os.getenv('PRIVATE_KEY', 'priv')
self.m = marvelous.api(
public_key=pub, private_key=priv, cache={
'name': 'testing_mock', 'expire_after': None})
public_key=pub, private_key=priv,
cache=marvelous.SqliteCache("testing_mock.db"))

def test_pulls_verbose(self):
week = self.m.comics({
Expand Down

0 comments on commit 2ae86ca

Please sign in to comment.