Skip to content

Commit

Permalink
Refactors code for currently supported Python 3.6 to 3.9 (#12)
Browse files Browse the repository at this point in the history
* Refactors code for currently supported Python 3.6 to 3.9

* Update .travis.yml

Yes I agree this is the better 'ugly' solution :-)

Co-authored-by: Jakob Hoeper <JKatzwinkel@users.noreply.github.com>

* updated requirements

* added missing then to travis yml

Co-authored-by: J0J0 T <2733783+JOJ0@users.noreply.github.com>
Co-authored-by: Jakob Hoeper <JKatzwinkel@users.noreply.github.com>
Co-authored-by: alifhughes <ali.fhughes@gmail.com>
  • Loading branch information
4 people committed Nov 15, 2020
1 parent 7428218 commit 536f2fa
Show file tree
Hide file tree
Showing 14 changed files with 57 additions and 110 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
dist/
.DS_Store
.mypy_cache
.coverage
env/
18 changes: 9 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
- "3.7"
- "3.8"
- "3.9"
install:
- pip install -r requirements.txt
script:
- nosetests --with-coverage --cover-package=discogs_client
script: |
if [ $(python -c "import sys; print(sys.version_info.minor)") -lt 7 ]; then
nosetests
else
nosetests --with-coverage --cover-package=discogs_client
fi
after_success:
- coveralls
matrix:
include:
- python: 3.3
dist: trusty
2 changes: 0 additions & 2 deletions discogs_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import absolute_import, division, print_function, unicode_literals

__version_info__ = 2, 2, 2
__version__ = '2.2.2'

Expand Down
26 changes: 4 additions & 22 deletions discogs_client/client.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
from __future__ import absolute_import, division, print_function, unicode_literals

import warnings
import json
try:
# python2
from urllib import urlencode
except ImportError:
# python3
from urllib.parse import urlencode
from urllib.parse import urlencode

from discogs_client import models
from discogs_client.exceptions import ConfigurationError, HTTPError, AuthorizationError
from discogs_client.utils import update_qs
from discogs_client.fetchers import RequestsFetcher, OAuth2Fetcher, UserTokenRequestsFetcher


class Client(object):
class Client:
_base_url = 'https://api.discogs.com'
_request_token_url = 'https://api.discogs.com/oauth/request_token'
_authorize_url = 'https://www.discogs.com/oauth/authorize'
Expand Down Expand Up @@ -73,9 +65,6 @@ def get_access_token(self, verifier):
"""
Uses the verifier to exchange a request token for an access token.
"""
if isinstance(verifier, bytes):
verifier = verifier.decode('utf8')

self._fetcher.set_verifier(verifier)

params = {}
Expand Down Expand Up @@ -112,7 +101,7 @@ def _request(self, method, url, data=None):
if status_code == 204:
return None

body = json.loads(content.decode('utf8'))
body = json.loads(content)

if 200 <= status_code < 300:
return body
Expand Down Expand Up @@ -141,14 +130,7 @@ def search(self, *query, **fields):
function are serialized into the request's query string.
"""
if query:
unicode_query = []
for q in query:
try:
unicode_q = q.decode('utf8')
except (UnicodeDecodeError, UnicodeEncodeError, AttributeError):
unicode_q = q
unicode_query.append(unicode_q)
fields['q'] = ' '.join(unicode_query)
fields['q'] = ' '.join(query)
return models.MixedPaginatedList(
self,
update_qs(self._base_url + '/database/search', fields),
Expand Down
3 changes: 0 additions & 3 deletions discogs_client/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
from __future__ import absolute_import, division, print_function, unicode_literals


class DiscogsAPIError(Exception):
"""Root Exception class for Discogs API errors."""
pass
Expand Down
20 changes: 7 additions & 13 deletions discogs_client/fetchers.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import requests
from requests.api import request
from oauthlib import oauth1
import json
import os
import re
try:
# python2
from urlparse import parse_qsl
except ImportError:
# python3
from urllib.parse import parse_qsl
from urllib.parse import parse_qsl


class Fetcher(object):
class Fetcher:
"""
Base class for Fetchers, which wrap and normalize the APIs of various HTTP
libraries.
Expand All @@ -31,7 +25,7 @@ def fetch(self, client, method, url, data=None, headers=None, json=True):
raise NotImplementedError()


class LoggingDelegator(object):
class LoggingDelegator:
"""Wraps a fetcher and logs all requests."""
def __init__(self, fetcher):
self.fetcher = fetcher
Expand Down Expand Up @@ -84,8 +78,8 @@ def __init__(self, consumer_key, consumer_secret, token=None, secret=None):

def store_token_from_qs(self, query_string):
token_dict = dict(parse_qsl(query_string))
token = token_dict[b'oauth_token'].decode('utf8')
secret = token_dict[b'oauth_token_secret'].decode('utf8')
token = token_dict[b'oauth_token']
secret = token_dict[b'oauth_token_secret']
self.store_token(token, secret)
return token, secret

Expand Down Expand Up @@ -116,7 +110,7 @@ def fetch(self, client, method, url, data=None, headers=None, json_format=True):

class FilesystemFetcher(Fetcher):
"""Fetches from a directory of files."""
default_response = json.dumps({'message': 'Resource not found.'}).encode('utf8'), 404
default_response = json.dumps({'message': 'Resource not found.'}), 404
path_with_params = re.compile('(?P<dir>(\w+/)+)(?P<query>\w+)\?(?P<params>.*)')

def __init__(self, base_path):
Expand Down Expand Up @@ -183,7 +177,7 @@ def check_alternate_params(self, base_name, json):

class MemoryFetcher(Fetcher):
"""Fetches from a dict of URL -> (content, status_code)."""
default_response = json.dumps({'message': 'Resource not found.'}).encode('utf8'), 404
default_response = json.dumps({'message': 'Resource not found.'}), 404

def __init__(self, responses):
self.responses = responses
Expand Down
64 changes: 28 additions & 36 deletions discogs_client/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import sys

from six import with_metaclass

from discogs_client.exceptions import HTTPError
from discogs_client.utils import parse_timestamp, update_qs, omit_none


class SimpleFieldDescriptor(object):
class SimpleFieldDescriptor:
"""
An attribute that determines its value using the object's fetch() method.
Expand Down Expand Up @@ -40,7 +35,7 @@ def __set__(self, instance, value):
raise AttributeError("can't set attribute")


class ObjectFieldDescriptor(object):
class ObjectFieldDescriptor:
"""
An attribute that determines its value using the object's fetch() method,
and passes the resulting value through an APIObject.
Expand Down Expand Up @@ -79,7 +74,7 @@ def __set__(self, instance, value):
raise AttributeError("can't set attribute")


class ListFieldDescriptor(object):
class ListFieldDescriptor:
"""
An attribute that determines its value using the object's fetch() method,
and passes each item in the resulting list through an APIObject.
Expand All @@ -104,7 +99,7 @@ def __set__(self, instance, value):
raise AttributeError("can't set attribute")


class ObjectCollectionDescriptor(object):
class ObjectCollectionDescriptor:
"""
An attribute that determines its value by fetching a URL to a paginated
list of related objects, and passes each item in the resulting list through
Expand Down Expand Up @@ -138,7 +133,7 @@ def __set__(self, instance, value):
raise AttributeError("can't set attribute")


class Field(object):
class Field:
"""
A placeholder for a descriptor. Is transformed into a descriptor by the
APIObjectMeta metaclass when the APIObject classes are created.
Expand Down Expand Up @@ -175,18 +170,15 @@ class ObjectCollection(Field):


class APIObjectMeta(type):
def __new__(cls, name, bases, dict_):
for k, v in dict_.items():
def __new__(cls, name, bases, namespace):
for k, v in namespace.items():
if isinstance(v, Field):
dict_[k] = v.to_descriptor(k)
return super(APIObjectMeta, cls).__new__(cls, name, bases, dict_)
namespace[k] = v.to_descriptor(k)
return super(APIObjectMeta, cls).__new__(cls, name, bases, namespace)


class APIObject(with_metaclass(APIObjectMeta, object)):
def repr_str(self, string):
if sys.version_info < (3,):
return string.encode('utf-8')
return string
class APIObject(metaclass=APIObjectMeta):
pass


class PrimaryAPIObject(APIObject):
Expand Down Expand Up @@ -265,7 +257,7 @@ def fetch(self, key, default=None):
return self.data.get(key, default)


class BasePaginatedResponse(object):
class BasePaginatedResponse:
"""Base class for lists of objects spread across many URLs."""
def __init__(self, client, url):
self.client = client
Expand Down Expand Up @@ -456,7 +448,7 @@ def releases(self):
return MixedPaginatedList(self.client, self.fetch('releases_url'), 'releases')

def __repr__(self):
return self.repr_str('<Artist {0!r} {1!r}>'.format(self.id, self.name))
return '<Artist {0!r} {1!r}>'.format(self.id, self.name)


class Release(PrimaryAPIObject):
Expand Down Expand Up @@ -493,7 +485,7 @@ def master(self):
return None

def __repr__(self):
return self.repr_str('<Release {0!r} {1!r}>'.format(self.id, self.title))
return '<Release {0!r} {1!r}>'.format(self.id, self.title)


class Master(PrimaryAPIObject):
Expand All @@ -514,7 +506,7 @@ def __init__(self, client, dict_):
self.data['resource_url'] = '{0}/masters/{1}'.format(client._base_url, dict_['id'])

def __repr__(self):
return self.repr_str('<Master {0!r} {1!r}>'.format(self.id, self.title))
return '<Master {0!r} {1!r}>'.format(self.id, self.title)


class Label(PrimaryAPIObject):
Expand All @@ -535,7 +527,7 @@ def __init__(self, client, dict_):
self.data['resource_url'] = '{0}/labels/{1}'.format(client._base_url, dict_['id'])

def __repr__(self):
return self.repr_str('<Label {0!r} {1!r}>'.format(self.id, self.name))
return '<Label {0!r} {1!r}>'.format(self.id, self.name)


class User(PrimaryAPIObject):
Expand Down Expand Up @@ -574,7 +566,7 @@ def collection_folders(self):
return [CollectionFolder(self.client, d) for d in resp['folders']]

def __repr__(self):
return self.repr_str('<User {0!r} {1!r}>'.format(self.id, self.username))
return '<User {0!r} {1!r}>'.format(self.id, self.username)


class WantlistItem(PrimaryAPIObject):
Expand All @@ -588,7 +580,7 @@ def __init__(self, client, dict_):
super(WantlistItem, self).__init__(client, dict_)

def __repr__(self):
return self.repr_str('<WantlistItem {0!r} {1!r}>'.format(self.id, self.release.title))
return '<WantlistItem {0!r} {1!r}>'.format(self.id, self.release.title)


# TODO: folder_id should be a Folder object; needs folder_url
Expand All @@ -604,7 +596,7 @@ def __init__(self, client, dict_):
super(CollectionItemInstance, self).__init__(client, dict_)

def __repr__(self):
return self.repr_str('<CollectionItemInstance {0!r} {1!r}>'.format(self.id, self.release.title))
return '<CollectionItemInstance {0!r} {1!r}>'.format(self.id, self.release.title)


class CollectionFolder(PrimaryAPIObject):
Expand All @@ -626,7 +618,7 @@ def add_release(self, release):
self.client._post(add_release_url, None)

def __repr__(self):
return self.repr_str('<CollectionFolder {0!r} {1!r}>'.format(self.id, self.name))
return '<CollectionFolder {0!r} {1!r}>'.format(self.id, self.name)


class List(PrimaryAPIObject):
Expand All @@ -644,7 +636,7 @@ def __init__(self, client, dict_):
self.data['resource_url'] = '{0}/lists/{1}'.format(client._base_url, dict_['id'])

def __repr__(self):
return self.repr_str('<List {0!r} {1!r}>'.format(self.id, self.name))
return '<List {0!r} {1!r}>'.format(self.id, self.name)


class Listing(PrimaryAPIObject):
Expand All @@ -667,7 +659,7 @@ def __init__(self, client, dict_):
self.data['resource_url'] = '{0}/marketplace/listings/{1}'.format(client._base_url, dict_['id'])

def __repr__(self):
return self.repr_str('<Listing {0!r} {1!r}>'.format(self.id, self.release.data['description']))
return '<Listing {0!r} {1!r}>'.format(self.id, self.release.data['description'])


class Order(PrimaryAPIObject):
Expand Down Expand Up @@ -700,7 +692,7 @@ def shipping(self, value):
self.changes['shipping'] = value

def __repr__(self):
return self.repr_str('<Order {0!r}>'.format(self.id))
return '<Order {0!r}>'.format(self.id)


class OrderMessage(SecondaryAPIObject):
Expand All @@ -711,7 +703,7 @@ class OrderMessage(SecondaryAPIObject):
timestamp = SimpleField(transform=parse_timestamp)

def __repr__(self):
return self.repr_str('<OrderMessage to:{0!r}>'.format(self.to.username))
return '<OrderMessage to:{0!r}>'.format(self.to.username)


class Track(SecondaryAPIObject):
Expand All @@ -722,15 +714,15 @@ class Track(SecondaryAPIObject):
credits = ListField('Artist', key='extraartists')

def __repr__(self):
return self.repr_str('<Track {0!r} {1!r}>'.format(self.position, self.title))
return '<Track {0!r} {1!r}>'.format(self.position, self.title)


class Price(SecondaryAPIObject):
currency = SimpleField()
value = SimpleField()

def __repr__(self):
return self.repr_str('<Price {0!r} {1!r}>'.format(self.value, self.currency))
return '<Price {0!r} {1!r}>'.format(self.value, self.currency)


class Video(SecondaryAPIObject):
Expand All @@ -741,7 +733,7 @@ class Video(SecondaryAPIObject):
url = SimpleField(key='uri')

def __repr__(self):
return self.repr_str('<Video {0!r}>'.format(self.title))
return '<Video {0!r}>'.format(self.title)


class ListItem(SecondaryAPIObject):
Expand All @@ -753,7 +745,7 @@ class ListItem(SecondaryAPIObject):
url = SimpleField(key='uri')

def __repr__(self):
return self.repr_str('<ListItem {0!r}>'.format(self.id))
return '<ListItem {0!r}>'.format(self.id)


CLASS_MAP = {
Expand Down
2 changes: 0 additions & 2 deletions discogs_client/tests/test_core.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import absolute_import, division, print_function, unicode_literals

import unittest
from discogs_client import Client
from discogs_client.tests import DiscogsClientTestCase
Expand Down

0 comments on commit 536f2fa

Please sign in to comment.