BigW Consortium Gitlab
Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
etsy-python
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Forest Godfrey
etsy-python
Commits
3ca4e347
Commit
3ca4e347
authored
May 31, 2010
by
Dan McKinley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added basic client-side type checking. readme update about how to run the tests.
parent
8efaf857
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
192 additions
and
39 deletions
+192
-39
README.md
README.md
+13
-0
_core.py
etsy/_core.py
+78
-7
test_core.py
test/test_core.py
+75
-32
test_v1.py
test/test_v1.py
+11
-0
util.py
test/util.py
+15
-0
No files found.
README.md
View file @
3ca4e347
...
...
@@ -79,6 +79,18 @@ api = Etsy(key_file='/usr/share/etsy/keys')
</pre>
## Tests
This package comes with a reasonably complete unit test suite. In order to run
the tests, use:
<pre>
$ python setup.py test
</pre>
Some of the tests (those that actually call the Etsy API) require your API key
to be locally configured. See the Configuration section, above.
## Future Work
...
...
@@ -92,6 +104,7 @@ There will be enhancements in the future to address this problem in a number of
### Version 0.2 - in progress
*
Added support for the v2 API
*
Added local configuration (~/.etsy) to eliminate cutting & pasting of api keys.
*
Added client-side type checking for parameters.
*
Added a test suite.
*
Added module to PyPI.
...
...
etsy/_core.py
View file @
3ca4e347
...
...
@@ -8,6 +8,67 @@ import os
class
TypeChecker
(
object
):
def
__init__
(
self
):
self
.
checkers
=
{
'int'
:
self
.
check_int
,
'float'
:
self
.
check_float
,
'string'
:
self
.
check_string
,
}
def
__call__
(
self
,
method
,
**
kwargs
):
params
=
method
[
'params'
]
for
k
,
v
in
kwargs
.
items
():
if
k
not
in
params
:
raise
ValueError
(
'Unexpected argument:
%
s=
%
s'
%
(
k
,
v
))
t
=
params
[
k
]
checker
=
self
.
checkers
.
get
(
t
,
None
)
or
self
.
compile
(
t
)
ok
,
converted
=
checker
(
v
)
if
not
ok
:
raise
ValueError
(
"Bad value for parameter
%
s of type '
%
s' -
%
s"
%
(
k
,
t
,
v
))
kwargs
[
k
]
=
converted
def
compile
(
self
,
t
):
if
t
.
startswith
(
'enum'
):
f
=
self
.
compile_enum
(
t
)
else
:
f
=
self
.
always_ok
self
.
checkers
[
t
]
=
f
return
f
def
compile_enum
(
self
,
t
):
terms
=
[
x
.
strip
()
for
x
in
t
[
5
:
-
1
]
.
split
(
','
)]
def
check_enum
(
value
):
return
(
value
in
terms
),
value
return
check_enum
def
always_ok
(
self
,
value
):
return
True
,
value
def
check_int
(
self
,
value
):
return
isinstance
(
value
,
int
),
value
def
check_float
(
self
,
value
):
if
isinstance
(
value
,
int
):
return
True
,
value
return
isinstance
(
value
,
float
),
value
def
check_string
(
self
,
value
):
return
isinstance
(
value
,
basestring
),
value
class
API
(
object
):
def
__init__
(
self
,
api_key
=
''
,
key_file
=
None
):
if
not
getattr
(
self
,
'api_url'
,
None
):
...
...
@@ -24,11 +85,16 @@ class API(object):
else
:
self
.
api_key
=
self
.
_read_key
(
key_file
)
self
.
type_checker
=
TypeChecker
()
d
=
JSONDecoder
()
self
.
decode
=
d
.
decode
for
method
in
self
.
_get_method_table
():
self
.
_create_method
(
**
method
)
ms
=
self
.
_get_method_table
()
self
.
_methods
=
dict
([(
m
[
'name'
],
m
)
for
m
in
ms
])
for
method
in
ms
:
self
.
_create_method
(
method
)
def
_get_method_table
(
self
):
...
...
@@ -47,12 +113,17 @@ class API(object):
return
gs
[
self
.
api_version
]
def
_create_method
(
self
,
name
,
description
,
uri
,
**
kw
):
def
_create_method
(
self
,
m
):
def
method
(
**
kwargs
):
return
self
.
_get
(
uri
,
**
kwargs
)
method
.
__name__
=
name
method
.
__doc__
=
description
setattr
(
self
,
name
,
method
)
return
self
.
_invoke
(
m
,
**
kwargs
)
method
.
__name__
=
m
[
'name'
]
method
.
__doc__
=
m
[
'description'
]
setattr
(
self
,
m
[
'name'
],
method
)
def
_invoke
(
self
,
m
,
**
kwargs
):
self
.
type_checker
(
m
,
**
kwargs
)
return
self
.
_get
(
m
[
'uri'
],
**
kwargs
)
def
_get_url
(
self
,
url
):
...
...
test/test_core.py
View file @
3ca4e347
from
__future__
import
with_statement
from
unittest
import
TestCase
from
etsy._core
import
API
from
cgi
import
parse_qs
from
urlparse
import
urlparse
import
os
from
util
import
Test
class
MockAPI
(
API
):
...
...
@@ -17,8 +16,12 @@ class MockAPI(API):
'http_method'
:
'GET'
,
'params'
:
{
'limit'
:
'int'
,
'test_id'
:
'
int
'
,
'test_id'
:
'
user_id_or_name
'
,
'offset'
:
'int'
,
'fizz'
:
'enum(foo, bar, baz)'
,
'buzz'
:
'float'
,
'blah'
:
'unknown type'
,
'kind'
:
'string'
,
},
'type'
:
'int'
,
'description'
:
'test method.'
}]
...
...
@@ -29,7 +32,7 @@ class MockAPI(API):
class
CoreTests
(
Test
Case
):
class
CoreTests
(
Test
):
def
setUp
(
self
):
self
.
api
=
MockAPI
(
'apikey'
)
...
...
@@ -71,49 +74,33 @@ class CoreTests(TestCase):
self
.
assertEquals
(
self
.
api
.
testMethod
.
__doc__
,
'test method.'
)
def
test_api_url_required
(
self
):
try
:
API
(
''
)
except
AssertionError
,
e
:
self
.
assertEqual
(
'No api_url configured.'
,
e
.
message
)
else
:
self
.
fail
(
'should have failed'
)
msg
=
self
.
assertRaises
(
AssertionError
,
API
,
''
)
self
.
assertEqual
(
'No api_url configured.'
,
msg
)
def
test_api_url_cannot_end_with_slash
(
self
):
class
Foo
(
API
):
api_url
=
'http://host/'
try
:
Foo
(
''
)
except
AssertionError
,
e
:
self
.
assertEqual
(
'api_url should not end with a slash.'
,
e
.
message
)
else
:
self
.
fail
(
'should have failed'
)
msg
=
self
.
assertRaises
(
AssertionError
,
Foo
,
''
)
self
.
assertEqual
(
'api_url should not end with a slash.'
,
msg
)
def
test_api_should_define_version
(
self
):
class
Foo
(
API
):
api_url
=
'http://host'
try
:
Foo
()
except
AssertionError
,
e
:
self
.
assertEqual
(
e
.
message
,
'API object should define api_version'
)
else
:
self
.
fail
(
'should have failed'
)
msg
=
self
.
assertRaises
(
AssertionError
,
Foo
)
self
.
assertEqual
(
msg
,
'API object should define api_version'
)
def
test_key_file_does_not_exist
(
self
):
try
:
MockAPI
(
key_file
=
'this does not exist'
)
except
AssertionError
,
e
:
self
.
assertTrue
(
"'this does not exist' does not exist"
in
e
.
message
)
else
:
self
.
fail
(
'should have failed'
)
msg
=
self
.
assertRaises
(
AssertionError
,
MockAPI
,
key_file
=
'this does not exist'
)
self
.
assertTrue
(
"'this does not exist' does not exist"
in
msg
)
def
test_reading_api_key
(
self
):
...
...
@@ -125,6 +112,62 @@ class CoreTests(TestCase):
os
.
unlink
(
'testkeys'
)
def
test_unrecognized_kwarg
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
not_an_arg
=
1
)
self
.
assertEqual
(
msg
,
'Unexpected argument: not_an_arg=1'
)
def
test_unknown_parameter_type_is_passed
(
self
):
self
.
api
.
testMethod
(
blah
=
1
)
self
.
assertEqual
(
self
.
last_query
()[
'blah'
],
[
'1'
])
def
test_parameter_type_int
(
self
):
self
.
api
.
testMethod
(
limit
=
5
)
self
.
assertEqual
(
self
.
last_query
()[
'limit'
],
[
'5'
])
def
bad_value_msg
(
self
,
name
,
t
,
v
):
return
"Bad value for parameter
%
s of type '
%
s' -
%
s"
%
(
name
,
t
,
v
)
def
test_invalid_parameter_type_int
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
limit
=
5.6
)
self
.
assertEqual
(
msg
,
self
.
bad_value_msg
(
'limit'
,
'int'
,
5.6
))
def
test_parameter_type_float
(
self
):
self
.
api
.
testMethod
(
buzz
=
42.1
)
self
.
assertEqual
(
self
.
last_query
()[
'buzz'
],
[
'42.1'
])
def
test_invalid_parameter_type_float
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
buzz
=
'x'
)
self
.
assertEqual
(
msg
,
self
.
bad_value_msg
(
'buzz'
,
'float'
,
'x'
))
def
test_int_accepted_as_float
(
self
):
self
.
api
.
testMethod
(
buzz
=
3
)
self
.
assertEqual
(
self
.
last_query
()[
'buzz'
],
[
'3'
])
def
test_parameter_type_enum
(
self
):
self
.
api
.
testMethod
(
fizz
=
'bar'
)
self
.
assertEqual
(
self
.
last_query
()[
'fizz'
],
[
'bar'
])
def
test_invalid_parameter_type_enum
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
fizz
=
'goo'
)
self
.
assertEqual
(
msg
,
self
.
bad_value_msg
(
'fizz'
,
'enum(foo, bar, baz)'
,
'goo'
))
def
test_parameter_type_string
(
self
):
self
.
api
.
testMethod
(
kind
=
'blah'
)
self
.
assertEqual
(
self
.
last_query
()[
'kind'
],
[
'blah'
])
def
test_invalid_parameter_type_string
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
kind
=
Test
)
self
.
assertEqual
(
msg
,
self
.
bad_value_msg
(
'kind'
,
'string'
,
Test
))
test/test_v1.py
0 → 100644
View file @
3ca4e347
from
__future__
import
with_statement
from
unittest
import
TestCase
from
etsy
import
EtsyV1
as
Etsy
class
V1Tests
(
TestCase
):
def
test_v1_api_works
(
self
):
api
=
Etsy
()
x
=
api
.
getUserDetails
(
user_id
=
'mcfunley'
)
self
.
assertEqual
(
x
[
0
][
'user_name'
],
'mcfunley'
)
test/util.py
0 → 100644
View file @
3ca4e347
from
unittest
import
TestCase
class
Test
(
TestCase
):
def
assertRaises
(
self
,
cls
,
f
,
*
args
,
**
kwargs
):
try
:
f
(
*
args
,
**
kwargs
)
except
cls
,
e
:
return
e
.
message
else
:
name
=
cls
.
__name__
if
hasattr
(
cls
,
'__name__'
)
else
str
(
cls
)
raise
self
.
failureException
,
"
%
s not raised"
%
name
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment