BigW Consortium Gitlab

Commit a2567f60 by Joe Paul

Fix HTTP body none issue

parent a3eac450
{}
\ No newline at end of file
language: python
python:
- "2.7"
# command to install dependencies
install: "pip install -r requirements_dev.txt"
# before script run flake8
before_script: flake8 .
# command to run tests
script: python -m pytest test
...@@ -19,7 +19,7 @@ $ python setup.py build ...@@ -19,7 +19,7 @@ $ python setup.py build
$ sudo python setup.py install $ sudo python setup.py install
</pre> </pre>
## Simple Example ## Example without authentication
To use, first [register for an Etsy developer key](http://developer.etsy.com/). To use, first [register for an Etsy developer key](http://developer.etsy.com/).
Below is an example session. Below is an example session.
...@@ -37,6 +37,29 @@ Type "help", "copyright", "credits" or "license" for more information. ...@@ -37,6 +37,29 @@ Type "help", "copyright", "credits" or "license" for more information.
</pre> </pre>
## Example with authentication
To use, first [register for an Etsy developer key](http://developer.etsy.com/).
Below is an example session.
<pre>
$ python
python
Python 2.7.11+ (default, Apr 17 2016, 14:00:29)
[GCC 5.3.1 20160413] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from etsy import Etsy
>>> from etsy.oauth import EtsyOAuthClient
>>> from etsy import EtsyEnvProduction
>>> etsy_env = EtsyEnvProduction()
>>> etsy_oauth_client = EtsyOAuthClient('consumer_token','consumer_secret')
>>> signin_url = etsy_oauth_client.get_signin_url()
>>> etsy_oauth_client.set_oauth_verifier(verifier_received_from_signin_url)
>>> etsy_api = Etsy(etsy_oauth_client=etsy_oauth_client, etsy_env=etsy_env)
>>> etsy_api.getUser(user_id="__SELF__")
</pre>
See also [this blog post](http://codeascraft.etsy.com/2010/04/22/announcing-etsys-new-api/) See also [this blog post](http://codeascraft.etsy.com/2010/04/22/announcing-etsys-new-api/)
on Code as Craft. on Code as Craft.
......
from _v2 import EtsyV2 as Etsy from _v2 import EtsyV2 as Etsy # noqa
from etsy_env import EtsyEnvSandbox, EtsyEnvProduction from etsy_env import EtsyEnvProduction # noqa
__version__ = '0.3.1' __version__ = '0.3.1'
__author__ = 'Dan McKinley' __author__ = 'Dan McKinley & Fulfil.IO Inc.'
__copyright__ = 'Copyright 2010, Etsy Inc.' __copyright__ = 'Copyright 2010, Etsy Inc.'
__license__ = 'GPL v3' __license__ = 'GPL v3'
__email__ = 'dan@etsy.com' __email__ = 'dan@etsy.com'
...@@ -13,25 +13,24 @@ from _multipartformdataencode import encode_multipart_formdata ...@@ -13,25 +13,24 @@ from _multipartformdataencode import encode_multipart_formdata
missing = object() missing = object()
class TypeChecker(object): class TypeChecker(object):
def __init__(self): def __init__(self):
self.checkers = { self.checkers = {
'int': self.check_int, 'int': self.check_int,
'float': self.check_float, 'float': self.check_float,
'string': self.check_string, 'string': self.check_string,
} }
def __call__(self, method, **kwargs): def __call__(self, method, **kwargs):
params = method['params'] params = method['params']
for k, v in kwargs.items(): for k, v in kwargs.items():
if k == 'includes': continue if k == 'includes':
continue
if k not in params: if k not in params:
raise ValueError('Unexpected argument: %s=%s' % (k, v)) raise ValueError('Unexpected argument: %s=%s' % (k, v))
t = params[k] t = params[k]
checker = self.checkers.get(t, None) or self.compile(t) checker = self.checkers.get(t, None) or self.compile(t)
ok, converted = checker(v) ok, converted = checker(v)
...@@ -40,7 +39,6 @@ class TypeChecker(object): ...@@ -40,7 +39,6 @@ class TypeChecker(object):
"Bad value for parameter %s of type '%s' - %s" % (k, t, v)) "Bad value for parameter %s of type '%s' - %s" % (k, t, v))
kwargs[k] = converted kwargs[k] = converted
def compile(self, t): def compile(self, t):
if t.startswith('enum'): if t.startswith('enum'):
f = self.compile_enum(t) f = self.compile_enum(t)
...@@ -49,37 +47,32 @@ class TypeChecker(object): ...@@ -49,37 +47,32 @@ class TypeChecker(object):
self.checkers[t] = f self.checkers[t] = f
return f return f
def compile_enum(self, t): def compile_enum(self, t):
terms = [x.strip() for x in t[5:-1].split(',')] terms = [x.strip() for x in t[5:-1].split(',')]
def check_enum(value): def check_enum(value):
return (value in terms), value return (value in terms), value
return check_enum return check_enum
def always_ok(self, value): def always_ok(self, value):
return True, value return True, value
def check_int(self, value): def check_int(self, value):
if isinstance(value, long): if isinstance(value, long): # noqa
return True, value return True, value
return isinstance(value, int), value return isinstance(value, int), value
def check_float(self, value): def check_float(self, value):
if isinstance(value, int): if isinstance(value, int):
return True, value return True, value
return isinstance(value, float), value return isinstance(value, float), value
def check_string(self, value): def check_string(self, value):
return isinstance(value, basestring), value return isinstance(value, basestring), value # noqa
class APIMethod(object): class APIMethod(object):
def __init__(self, api, spec): def __init__(self, api, spec):
""" """
Parameters: Parameters:
...@@ -92,7 +85,7 @@ class APIMethod(object): ...@@ -92,7 +85,7 @@ class APIMethod(object):
'string', 'materials': 'array(string)', 'shipping_template_id': 'string', 'materials': 'array(string)', 'shipping_template_id':
'int', 'quantity': 'int', 'shop_section_id': 'int'}, 'defaults': 'int', 'quantity': 'int', 'shop_section_id': 'int'}, 'defaults':
{'materials': None, 'shop_section_id': None}, 'type': 'Listing', {'materials': None, 'shop_section_id': None}, 'type': 'Listing',
'description': 'Creates a new Listing'} 'description': 'Creates a new Listing'}
""" """
self.api = api self.api = api
...@@ -100,14 +93,12 @@ class APIMethod(object): ...@@ -100,14 +93,12 @@ class APIMethod(object):
self.type_checker = self.api.type_checker self.type_checker = self.api.type_checker
self.__doc__ = self.spec['description'] self.__doc__ = self.spec['description']
self.compiled = False self.compiled = False
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
if not self.compiled: if not self.compiled:
self.compile() self.compile()
return self.invoke(*args, **kwargs) return self.invoke(*args, **kwargs)
def compile(self): def compile(self):
uri = self.spec['uri'] uri = self.spec['uri']
self.positionals = re.findall('{(.*)}', uri) self.positionals = re.findall('{(.*)}', uri)
...@@ -118,7 +109,6 @@ class APIMethod(object): ...@@ -118,7 +109,6 @@ class APIMethod(object):
self.compiled = True self.compiled = True
def invoke(self, *args, **kwargs): def invoke(self, *args, **kwargs):
if args and not self.positionals: if args and not self.positionals:
raise ValueError( raise ValueError(
...@@ -142,13 +132,12 @@ class APIMethod(object): ...@@ -142,13 +132,12 @@ class APIMethod(object):
del kwargs[p] del kwargs[p]
self.type_checker(self.spec, **kwargs) self.type_checker(self.spec, **kwargs)
return self.api._get(self.spec['http_method'], self.uri_format % ps, **kwargs) return (self.api._get(self.spec['http_method'],
self.uri_format % ps, **kwargs))
class MethodTableCache(object): class MethodTableCache(object):
max_age = 60*60*24 max_age = 60 * 60 * 24
def __init__(self, api, method_cache): def __init__(self, api, method_cache):
self.api = api self.api = api
...@@ -156,30 +145,25 @@ class MethodTableCache(object): ...@@ -156,30 +145,25 @@ class MethodTableCache(object):
self.used_cache = False self.used_cache = False
self.wrote_cache = False self.wrote_cache = False
def resolve_file(self, method_cache): def resolve_file(self, method_cache):
if method_cache is missing: if method_cache is missing:
return self.default_file() return self.default_file()
return method_cache return method_cache
def etsy_home(self): def etsy_home(self):
return self.api.etsy_home() return self.api.etsy_home()
def default_file(self): def default_file(self):
etsy_home = self.etsy_home() etsy_home = self.etsy_home()
d = etsy_home if os.path.isdir(etsy_home) else tempfile.gettempdir() d = etsy_home if os.path.isdir(etsy_home) else tempfile.gettempdir()
return os.path.join(d, 'methods.%s.json' % self.api.api_version) return os.path.join(d, 'methods.%s.json' % self.api.api_version)
def get(self): def get(self):
ms = self.get_cached() ms = self.get_cached()
if not ms: if not ms:
ms = self.api.get_method_table() ms = self.api.get_method_table()
self.cache(ms) self.cache(ms)
return ms return ms
def get_cached(self): def get_cached(self):
if self.filename is None or not os.path.isfile(self.filename): if self.filename is None or not os.path.isfile(self.filename):
...@@ -193,10 +177,10 @@ class MethodTableCache(object): ...@@ -193,10 +177,10 @@ class MethodTableCache(object):
self.api.log('Reading method table cache: %s' % self.filename) self.api.log('Reading method table cache: %s' % self.filename)
return json.loads(f.read()) return json.loads(f.read())
def cache(self, methods): def cache(self, methods):
if self.filename is None: if self.filename is None:
self.api.log('Method table caching disabled, not writing new cache.') self.api.log(
'Method table caching disabled, not writing new cache.')
return return
with open(self.filename, 'w') as f: with open(self.filename, 'w') as f:
json.dump(methods, f) json.dump(methods, f)
...@@ -204,22 +188,21 @@ class MethodTableCache(object): ...@@ -204,22 +188,21 @@ class MethodTableCache(object):
self.api.log('Wrote method table cache: %s' % self.filename) self.api.log('Wrote method table cache: %s' % self.filename)
class API(object): class API(object):
def __init__(self, api_key='', key_file=None, method_cache=missing,
def __init__(self, api_key='', key_file=None, method_cache=missing,
log=None): log=None):
""" """
Creates a new API instance. When called with no arguments, Creates a new API instance. When called with no arguments,
reads the appropriate API key from the default ($HOME/.etsy/keys) reads the appropriate API key from the default ($HOME/.etsy/keys)
file. file.
Parameters: Parameters:
api_key - An explicit API key to use. api_key - An explicit API key to use.
key_file - A file to read the API keys from. key_file - A file to read the API keys from.
method_cache - A file to save the API method table in for method_cache - A file to save the API method table in for
24 hours. This speeds up the creation of API 24 hours. This speeds up the creation of API
objects. objects.
log - An callable that accepts a string parameter. log - An callable that accepts a string parameter.
Receives log messages. No logging is done if Receives log messages. No logging is done if
this is None. this is None.
...@@ -227,9 +210,9 @@ class API(object): ...@@ -227,9 +210,9 @@ class API(object):
Only one of api_key and key_file may be passed. Only one of api_key and key_file may be passed.
If method_cache is explicitly set to None, no method table If method_cache is explicitly set to None, no method table
caching is performed. If the parameter is not passed, a file in caching is performed. If the parameter is not passed, a file in
$HOME/.etsy is used if that directory exists. Otherwise, a $HOME/.etsy is used if that directory exists. Otherwise, a
temp file is used. temp file is used.
""" """
if not getattr(self, 'api_url', None): if not getattr(self, 'api_url', None):
raise AssertionError('No api_url configured.') raise AssertionError('No api_url configured.')
...@@ -244,10 +227,11 @@ class API(object): ...@@ -244,10 +227,11 @@ class API(object):
raise AssertionError('Keys can be read from a file or passed, ' raise AssertionError('Keys can be read from a file or passed, '
'but not both.') 'but not both.')
if api_key: if self.etsy_oauth_client is None:
self.api_key = api_key if api_key:
else: self.api_key = api_key
self.api_key = self._read_key(key_file) else:
self.api_key = self._read_key(key_file)
self.log = log or self._ignore self.log = log or self._ignore
if not callable(self.log): if not callable(self.log):
...@@ -258,15 +242,12 @@ class API(object): ...@@ -258,15 +242,12 @@ class API(object):
self.decode = json.loads self.decode = json.loads
self.log('Creating %s Etsy API, base url=%s.' % ( self.log('Creating %s Etsy API, base url=%s.' % (
self.api_version, self.api_url)) self.api_version, self.api_url))
self._get_methods(method_cache) self._get_methods(method_cache)
def _ignore(self, _): def _ignore(self, _):
pass pass
def _get_methods(self, method_cache): def _get_methods(self, method_cache):
self.method_cache = MethodTableCache(self, method_cache) self.method_cache = MethodTableCache(self, method_cache)
ms = self.method_cache.get() ms = self.method_cache.get()
...@@ -277,15 +258,12 @@ class API(object): ...@@ -277,15 +258,12 @@ class API(object):
# self.log('API._get_methods: self._methods = %r' % self._methods) # self.log('API._get_methods: self._methods = %r' % self._methods)
def etsy_home(self): def etsy_home(self):
return os.path.expanduser('~/.etsy') return os.path.expanduser('~/.etsy')
def get_method_table(self): def get_method_table(self):
return self._get('GET', '/') return self._get('GET', '/')
def _read_key(self, key_file): def _read_key(self, key_file):
key_file = key_file or os.path.join(self.etsy_home(), 'keys') key_file = key_file or os.path.join(self.etsy_home(), 'keys')
if not os.path.isfile(key_file): if not os.path.isfile(key_file):
...@@ -294,22 +272,21 @@ class API(object): ...@@ -294,22 +272,21 @@ class API(object):
'pass an API key explicitly.' % key_file) 'pass an API key explicitly.' % key_file)
gs = {} gs = {}
execfile(key_file, gs) execfile(key_file, gs) # noqa
return gs[self.api_version] return gs[self.api_version]
def _get_url(self, url, http_method, content_type, body): def _get_url(self, url, http_method, content_type, body):
self.log("API._get_url: url = %r" % url) self.log("API._get_url: url = %r" % url)
with closing(urllib2.urlopen(url)) as f: with closing(urllib2.urlopen(url)) as f:
return f.read() return f.read()
def _get(self, http_method, url, **kwargs): def _get(self, http_method, url, **kwargs):
kwargs.update(dict(api_key=self.api_key)) if self.etsy_oauth_client is None:
kwargs.update(dict(api_key=self.api_key))
if http_method == 'GET': if http_method == 'GET':
url = '%s%s?%s' % (self.api_url, url, urlencode(kwargs)) url = '%s%s?%s' % (self.api_url, url, urlencode(kwargs))
body = None body = ''
content_type = None content_type = None
elif http_method == 'POST': elif http_method == 'POST':
url = '%s%s' % (self.api_url, url) url = '%s%s' % (self.api_url, url)
...@@ -327,13 +304,14 @@ class API(object): ...@@ -327,13 +304,14 @@ class API(object):
self.last_url = url self.last_url = url
data = self._get_url(url, http_method, content_type, body) data = self._get_url(url, http_method, content_type, body)
self.log('API._get: http_method = %r, url = %r, data = %r' % (http_method, url, data)) self.log('API._get: http_method = %r, url = %r, data = %r' %
(http_method, url, data))
try: try:
self.data = self.decode(data) self.data = self.decode(data)
except json.JSONDecodeError: except json.JSONDecodeError:
raise ValueError('Could not decode response from Etsy as JSON: %r' % data) raise ValueError(
'Could not decode response from Etsy as JSON: %r' % data)
self.count = self.data['count'] self.count = self.data['count']
return self.data['results'] return self.data['results']
...@@ -6,10 +6,12 @@ Functions for encoding multipart/form-data ...@@ -6,10 +6,12 @@ Functions for encoding multipart/form-data
From http://code.activestate.com/recipes/146306/ (PSF License) From http://code.activestate.com/recipes/146306/ (PSF License)
""" """
def encode_multipart_formdata(fields, files): def encode_multipart_formdata(fields, files):
""" """
fields is a sequence of (name, value) elements for regular form fields. fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value) elements for data to be uploaded as files files is a sequence of (name, filename, value) elements for data to be
uploaded as files
Return (content_type, body) ready for httplib.HTTP instance Return (content_type, body) ready for httplib.HTTP instance
""" """
BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$' BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
...@@ -22,7 +24,9 @@ def encode_multipart_formdata(fields, files): ...@@ -22,7 +24,9 @@ def encode_multipart_formdata(fields, files):
L.append(value) L.append(value)
for (key, filename, value) in files: for (key, filename, value) in files:
L.append('--' + BOUNDARY) L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename)) L.append(
'Content-Disposition: '
'form-data; name="%s"; filename="%s"' % (key, filename))
L.append('Content-Type: %s' % get_content_type(filename)) L.append('Content-Type: %s' % get_content_type(filename))
L.append('') L.append('')
L.append(value) L.append(value)
...@@ -32,6 +36,6 @@ def encode_multipart_formdata(fields, files): ...@@ -32,6 +36,6 @@ def encode_multipart_formdata(fields, files):
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
return content_type, body return content_type, body
def get_content_type(filename):
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
def get_content_type(filename):
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
import urllib import urllib # noqa
from _core import API, missing from _core import API, missing
from etsy_env import EtsyEnvSandbox, EtsyEnvProduction from etsy_env import EtsyEnvProduction
try: try:
from urlparse import parse_qsl from urlparse import parse_qsl # noqa
except ImportError: except ImportError:
from cgi import parse_qsl from cgi import parse_qsl # noqa
class EtsyV2(API): class EtsyV2(API):
api_version = 'v2' api_version = 'v2'
def __init__(self, api_key='', key_file=None, method_cache=missing, def __init__(self, api_key='', key_file=None, method_cache=missing,
etsy_env=EtsyEnvSandbox(), log=None, etsy_oauth_client=None): etsy_env=EtsyEnvProduction(), log=None,
etsy_oauth_client=None):
self.api_url = etsy_env.api_url self.api_url = etsy_env.api_url
self.etsy_oauth_client = None self.etsy_oauth_client = None
...@@ -22,5 +24,8 @@ class EtsyV2(API): ...@@ -22,5 +24,8 @@ class EtsyV2(API):
def _get_url(self, url, http_method, content_type, body): def _get_url(self, url, http_method, content_type, body):
if self.etsy_oauth_client is not None: if self.etsy_oauth_client is not None:
return self.etsy_oauth_client.do_oauth_request(url, http_method, content_type, body) return self.etsy_oauth_client.do_oauth_request(url,
http_method,
content_type,
body)
return API._get_url(self, url, http_method, content_type, body) return API._get_url(self, url, http_method, content_type, body)
class EtsyEnvSandbox(object): class EtsyEnvSandbox(object):
request_token_url = 'http://sandbox.openapi.etsy.com/v2/oauth/request_token' request_token_url = \
access_token_url = 'http://sandbox.openapi.etsy.com/v2/oauth/access_token' 'https://sandbox.openapi.etsy.com/v2/oauth/request_token'
access_token_url = 'https://sandbox.openapi.etsy.com/v2/oauth/access_token'
signin_url = 'https://www.etsy.com/oauth/signin' signin_url = 'https://www.etsy.com/oauth/signin'
api_url = 'http://sandbox.openapi.etsy.com/v2' api_url = 'https://sandbox.openapi.etsy.com/v2'
class EtsyEnvProduction(object): class EtsyEnvProduction(object):
request_token_url = 'http://openapi.etsy.com/v2/oauth/request_token' request_token_url = 'https://openapi.etsy.com/v2/oauth/request_token'
access_token_url = 'http://openapi.etsy.com/v2/oauth/access_token' access_token_url = 'https://openapi.etsy.com/v2/oauth/access_token'
signin_url = 'https://www.etsy.com/oauth/signin' signin_url = 'https://www.etsy.com/oauth/signin'
api_url = 'http://openapi.etsy.com/v2' api_url = 'https://openapi.etsy.com/v2'
import oauth2 as oauth import oauth2 as oauth
import urllib import urllib
from cgi import parse_qsl from cgi import parse_qsl
from etsy_env import EtsyEnvSandbox, EtsyEnvProduction from etsy_env import EtsyEnvProduction
EtsyOAuthToken = oauth.Token EtsyOAuthToken = oauth.Token
class EtsyOAuthClient(oauth.Client): class EtsyOAuthClient(oauth.Client):
def __init__(self, oauth_consumer_key, oauth_consumer_secret, etsy_env=EtsyEnvSandbox(), token=None, logger=None):
def __init__(self, oauth_consumer_key,
oauth_consumer_secret, etsy_env=EtsyEnvProduction(),
token=None, logger=None):
consumer = oauth.Consumer(oauth_consumer_key, oauth_consumer_secret) consumer = oauth.Consumer(oauth_consumer_key, oauth_consumer_secret)
super(EtsyOAuthClient, self).__init__(consumer) super(EtsyOAuthClient, self).__init__(consumer)
self.request_token_url = etsy_env.request_token_url self.request_token_url = etsy_env.request_token_url
...@@ -16,17 +20,19 @@ class EtsyOAuthClient(oauth.Client): ...@@ -16,17 +20,19 @@ class EtsyOAuthClient(oauth.Client):
self.logger = logger self.logger = logger
def get_request_token(self, **kwargs): def get_request_token(self, **kwargs):
request_token_url = '%s?%s' % (self.request_token_url, urllib.urlencode(kwargs)) request_token_url = '%s?%s' % (
self.request_token_url, urllib.urlencode(kwargs))
resp, content = self.request(request_token_url, 'GET') resp, content = self.request(request_token_url, 'GET')
return self._get_token(content) return self._get_token(content)
def get_signin_url(self, **kwargs): def get_signin_url(self, **kwargs):
self.token = self.get_request_token(**kwargs) self.token = self.get_request_token(**kwargs)
if self.token is None: return None if self.token is None:
return None
return self.signin_url + '?' + \ return self.signin_url + '?' + \
urllib.urlencode({'oauth_token': self.token.key}) urllib.urlencode({'oauth_token': self.token.key})
def get_access_token(self, oauth_verifier): def get_access_token(self, oauth_verifier):
self.token.set_verifier(oauth_verifier) self.token.set_verifier(oauth_verifier)
...@@ -37,8 +43,10 @@ class EtsyOAuthClient(oauth.Client): ...@@ -37,8 +43,10 @@ class EtsyOAuthClient(oauth.Client):
self.token = self.get_access_token(oauth_verifier) self.token = self.get_access_token(oauth_verifier)
def do_oauth_request(self, url, http_method, content_type, body): def do_oauth_request(self, url, http_method, content_type, body):
if content_type and content_type != 'application/x-www-form-urlencoded': if (content_type and content_type !=
resp, content = self.request(url, http_method, body=body, headers={'Content-Type': content_type}) 'application/x-www-form-urlencoded'):
resp, content = self.request(url, http_method, body=body, headers={
'Content-Type': content_type})
else: else:
resp, content = self.request(url, http_method, body=body) resp, content = self.request(url, http_method, body=body)
...@@ -52,5 +60,5 @@ class EtsyOAuthClient(oauth.Client): ...@@ -52,5 +60,5 @@ class EtsyOAuthClient(oauth.Client):
try: try:
return oauth.Token(d['oauth_token'], d['oauth_token_secret']) return oauth.Token(d['oauth_token'], d['oauth_token_secret'])
except KeyError, e: except KeyError:
return None return None
#!/usr/bin/env python #!/usr/bin/env python
import os, sys import os
import sys
import oauth2 as oauth import oauth2 as oauth
import webbrowser import webbrowser
from etsy import Etsy, EtsyEnvSandbox, EtsyEnvProduction from etsy import Etsy, EtsyEnvProduction
from etsy.oauth import EtsyOAuthClient from etsy.oauth import EtsyOAuthClient
logging_enabled = True logging_enabled = True
etsy_env = EtsyEnvProduction() etsy_env = EtsyEnvProduction()
def my_log(msg): def my_log(msg):
if logging_enabled: print(msg) if logging_enabled:
print(msg)
def write_config_file(oauth_token): def write_config_file(oauth_token):
os.umask(0077) os.umask(0077) # noqa
config_file = file('config.py', 'w') config_file = file('config.py', 'w')
if config: if config:
config_file.write("oauth_consumer_key = %r\n" % config.oauth_consumer_key) config_file.write("oauth_consumer_key = %r\n" %
config_file.write("oauth_consumer_secret = %r\n" % config.oauth_consumer_secret) config.oauth_consumer_key)
config_file.write("oauth_consumer_secret = %r\n" %
config.oauth_consumer_secret)
if oauth_token: if oauth_token:
config_file.write("oauth_token_key = %r\n" % oauth_token.key) config_file.write("oauth_token_key = %r\n" % oauth_token.key)
...@@ -30,16 +36,20 @@ except ImportError: ...@@ -30,16 +36,20 @@ except ImportError:
config = None config = None
write_config_file(oauth_token=None) write_config_file(oauth_token=None)
if hasattr(config, 'oauth_consumer_key') and hasattr(config, 'oauth_consumer_secret'): if (hasattr(config, 'oauth_consumer_key') and
hasattr(config, 'oauth_consumer_secret')):
oauth_client = EtsyOAuthClient( oauth_client = EtsyOAuthClient(
oauth_consumer_key=config.oauth_consumer_key, oauth_consumer_key=config.oauth_consumer_key,
oauth_consumer_secret=config.oauth_consumer_secret, oauth_consumer_secret=config.oauth_consumer_secret,
etsy_env=etsy_env) etsy_env=etsy_env)
else: else:
sys.stderr.write('ERROR: You must set oauth_consumer_key and oauth_consumer_secret in config.py\n') sys.stderr.write(
'ERROR: You must set oauth_consumer_key and '
'oauth_consumer_secret in config.py\n')
sys.exit(1) sys.exit(1)
if hasattr(config, 'oauth_token_key') and hasattr(config, 'oauth_token_secret'): if (hasattr(config, 'oauth_token_key') and
hasattr(config, 'oauth_token_secret')):
oauth_client.token = oauth.Token( oauth_client.token = oauth.Token(
key=config.oauth_token_key, key=config.oauth_token_key,
secret=config.oauth_token_secret) secret=config.oauth_token_secret)
...@@ -50,17 +60,21 @@ else: ...@@ -50,17 +60,21 @@ else:
etsy_api = Etsy(etsy_oauth_client=oauth_client, etsy_env=etsy_env, log=my_log) etsy_api = Etsy(etsy_oauth_client=oauth_client, etsy_env=etsy_env, log=my_log)
# print 'oauth access token: (key=%r; secret=%r)' % (oauth_client.token.key, oauth_client.token.secret) # print 'oauth access token: (key=%r; secret=%r)' %
# (oauth_client.token.key, oauth_client.token.secret)
print('findAllShopListingsActive => %r' % etsy_api.findAllShopListingsActive(shop_id=config.user_id, sort_on='created', limit=1)) print('findAllShopListingsActive => %r' % etsy_api.findAllShopListingsActive(
shop_id=config.user_id, sort_on='created', limit=1))
# print('getListing => %r' % etsy_api.getListing(listing_id=63067548)) # print('getListing => %r' % etsy_api.getListing(listing_id=63067548))
print('findAllUserShippingTemplates => %r' % etsy_api.findAllUserShippingTemplates(user_id=config.user_id)) print('findAllUserShippingTemplates => %r' %
etsy_api.findAllUserShippingTemplates(user_id=config.user_id))
def testCreateListing(): def testCreateListing():
print "Creating listing..." print "Creating listing..."
result = etsy_api.createListing( result = etsy_api.createListing(
description=config.description, description=config.description,
title=config.title, title=config.title,
...@@ -75,9 +89,9 @@ def testCreateListing(): ...@@ -75,9 +89,9 @@ def testCreateListing():
print "Created listing with listing id %d" % listing_id print "Created listing with listing id %d" % listing_id
result = etsy_api.uploadListingImage(listing_id=listing_id, image=config.image_file) result = etsy_api.uploadListingImage(listing_id=listing_id,
image=config.image_file)
print "Result of uploading image: %r" % result print "Result of uploading image: %r" % result
testCreateListing() testCreateListing()
pip==8.1.2
httplib2==0.9.2
oauth2==1.9.0.post1
simplejson==3.8.2
flake8==2.6.0
pytest==2.9.2
\ No newline at end of file
...@@ -5,19 +5,26 @@ from setuptools import setup ...@@ -5,19 +5,26 @@ from setuptools import setup
this_dir = os.path.realpath(os.path.dirname(__file__)) this_dir = os.path.realpath(os.path.dirname(__file__))
long_description = open(os.path.join(this_dir, 'README.md'), 'r').read() long_description = open(os.path.join(this_dir, 'README.md'), 'r').read()
requirements = [
]
test_requirements = [
'pytest',
]
setup( setup(
name = 'etsy', name='etsy',
version = '0.3.1', version='0.3.1',
author = 'Dan McKinley', author='Dan McKinley & Fulfil.IO Inc.',
author_email = 'dan@etsy.com', author_email='dan@etsy.com',
description = 'Python access to the Etsy API', description='Python access to the Etsy API',
license = 'GPL v3', license='GPL v3',
keywords = 'etsy api handmade', keywords='etsy api handmade',
packages = ['etsy'], packages=['etsy'],
long_description = long_description, long_description=long_description,
test_suite = 'test', test_suite='test',
install_requires=['simplejson >= 2.0'], install_requires=['simplejson >= 2.0'],
extras_require = { extras_require={
'OAuth': ["oauth2>=1.2.0"], 'OAuth': ["oauth2>=1.2.0"],
} }
) )
...@@ -10,28 +10,22 @@ class Test(TestCase): ...@@ -10,28 +10,22 @@ class Test(TestCase):
scratch_dir = os.path.join(this_dir, 'scratch') scratch_dir = os.path.join(this_dir, 'scratch')
def setUp(self): def setUp(self):
if not os.path.isdir(self.scratch_dir): if not os.path.isdir(self.scratch_dir):
os.mkdir(self.scratch_dir) os.mkdir(self.scratch_dir)
def tearDown(self): def tearDown(self):
self.delete_scratch() self.delete_scratch()
def delete_scratch(self): def delete_scratch(self):
if os.path.isdir(self.scratch_dir): if os.path.isdir(self.scratch_dir):
shutil.rmtree(self.scratch_dir) shutil.rmtree(self.scratch_dir)
def assertRaises(self, cls, f, *args, **kwargs): def assertRaises(self, cls, f, *args, **kwargs):
try: try:
f(*args, **kwargs) f(*args, **kwargs)
except cls, e: except cls, e: # noqa
return e.message return e.message
else: else:
name = cls.__name__ if hasattr(cls, '__name__') else str(cls) name = cls.__name__ if hasattr(cls, '__name__') else str(cls)
raise self.failureException, "%s not raised" % name raise self.failureException, "%s not raised" % name
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment