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
ab618211
Commit
ab618211
authored
May 31, 2010
by
Dan McKinley
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
support for positional arguments
parent
ae7170fb
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
97 additions
and
27 deletions
+97
-27
README.md
README.md
+1
-0
_core.py
etsy/_core.py
+47
-15
test_core.py
test/test_core.py
+49
-12
No files found.
README.md
View file @
ab618211
...
...
@@ -109,6 +109,7 @@ There will be enhancements in the future to address this problem in a number of
*
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 support for positional arguments.
*
Added a test suite.
*
Added module to PyPI.
...
...
etsy/_core.py
View file @
ab618211
...
...
@@ -5,6 +5,7 @@ import urllib2
from
urllib
import
urlencode
from
ConfigParser
import
ConfigParser
import
os
import
re
...
...
@@ -65,8 +66,52 @@ class TypeChecker(object):
def
check_string
(
self
,
value
):
return
isinstance
(
value
,
basestring
),
value
class
APIMethod
(
object
):
def
__init__
(
self
,
api
,
spec
):
self
.
api
=
api
self
.
spec
=
spec
self
.
type_checker
=
self
.
api
.
type_checker
self
.
__doc__
=
self
.
spec
[
'description'
]
self
.
compiled
=
False
def
__call__
(
self
,
*
args
,
**
kwargs
):
if
not
self
.
compiled
:
self
.
compile
()
return
self
.
invoke
(
*
args
,
**
kwargs
)
def
compile
(
self
):
self
.
positionals
=
re
.
findall
(
'{(.*)}'
,
self
.
spec
[
'uri'
])
self
.
compiled
=
True
def
invoke
(
self
,
*
args
,
**
kwargs
):
if
args
and
not
self
.
positionals
:
raise
ValueError
(
'Positional argument(s):
%
s provided, but this method does '
'not support them.'
%
(
args
,))
if
len
(
args
)
>
len
(
self
.
positionals
):
raise
ValueError
(
'Too many positional arguments.'
)
for
k
,
v
in
zip
(
self
.
positionals
,
args
):
if
k
in
kwargs
:
raise
ValueError
(
'Positional argument duplicated in kwargs:
%
s'
%
k
)
kwargs
[
k
]
=
v
for
p
in
self
.
positionals
:
if
p
not
in
kwargs
:
raise
ValueError
(
"Required argument '
%
s' not provided."
%
p
)
self
.
type_checker
(
self
.
spec
,
**
kwargs
)
return
self
.
api
.
_get
(
self
.
spec
[
'uri'
],
**
kwargs
)
class
API
(
object
):
...
...
@@ -94,7 +139,7 @@ class API(object):
self
.
_methods
=
dict
([(
m
[
'name'
],
m
)
for
m
in
ms
])
for
method
in
ms
:
se
lf
.
_create_method
(
method
)
se
tattr
(
self
,
method
[
'name'
],
APIMethod
(
self
,
method
)
)
def
_get_method_table
(
self
):
...
...
@@ -113,19 +158,6 @@ class API(object):
return
gs
[
self
.
api_version
]
def
_create_method
(
self
,
m
):
def
method
(
**
kwargs
):
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
):
with
closing
(
urllib2
.
urlopen
(
url
))
as
f
:
return
f
.
read
()
...
...
@@ -135,7 +167,7 @@ class API(object):
for
k
,
v
in
kwargs
.
items
():
arg
=
'{
%
s}'
%
k
if
arg
in
url
:
url
=
url
.
replace
(
arg
,
v
)
url
=
url
.
replace
(
arg
,
str
(
v
)
)
del
kwargs
[
k
]
kwargs
.
update
(
dict
(
api_key
=
self
.
api_key
))
...
...
test/test_core.py
View file @
ab618211
...
...
@@ -24,7 +24,13 @@ class MockAPI(API):
'kind'
:
'string'
,
},
'type'
:
'int'
,
'description'
:
'test method.'
}]
'description'
:
'test method.'
},
{
'name'
:
'noPositionals'
,
'uri'
:
'/blah'
,
'http_method'
:
'GET'
,
'params'
:
{
'foo'
:
'int'
},
'type'
:
'int'
,
'description'
:
'no pos arguments'
}]
def
_get_url
(
self
,
url
):
...
...
@@ -113,17 +119,18 @@ class CoreTests(Test):
def
test_unrecognized_kwarg
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
not_an_arg
=
1
)
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
test_id
=
1
,
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
.
api
.
testMethod
(
test_id
=
1
,
blah
=
1
)
self
.
assertEqual
(
self
.
last_query
()[
'blah'
],
[
'1'
])
def
test_parameter_type_int
(
self
):
self
.
api
.
testMethod
(
limit
=
5
)
self
.
api
.
testMethod
(
test_id
=
1
,
limit
=
5
)
self
.
assertEqual
(
self
.
last_query
()[
'limit'
],
[
'5'
])
...
...
@@ -131,43 +138,73 @@ class CoreTests(Test):
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
)
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
test_id
=
1
,
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
.
api
.
testMethod
(
test_id
=
1
,
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'
)
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
test_id
=
1
,
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
.
api
.
testMethod
(
test_id
=
1
,
buzz
=
3
)
self
.
assertEqual
(
self
.
last_query
()[
'buzz'
],
[
'3'
])
def
test_parameter_type_enum
(
self
):
self
.
api
.
testMethod
(
fizz
=
'bar'
)
self
.
api
.
testMethod
(
test_id
=
1
,
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'
)
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
test_id
=
1
,
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
.
api
.
testMethod
(
test_id
=
1
,
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
)
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
test_id
=
1
,
kind
=
Test
)
self
.
assertEqual
(
msg
,
self
.
bad_value_msg
(
'kind'
,
'string'
,
Test
))
def
test_url_arguments_work_positionally
(
self
):
self
.
api
.
testMethod
(
'foo'
)
self
.
assertEqual
(
self
.
api
.
last_url
,
'http://host/test/foo?api_key=apikey'
)
def
test_method_with_no_positionals_doesnt_accept_them
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
noPositionals
,
1
,
2
)
self
.
assertEqual
(
'Positional argument(s): (1, 2) provided, but this '
'method does not support them.'
,
msg
)
def
test_too_many_positionals
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
1
,
2
)
self
.
assertEqual
(
'Too many positional arguments.'
,
msg
)
def
test_positional_argument_not_provided
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
)
self
.
assertEqual
(
"Required argument 'test_id' not provided."
,
msg
)
def
test_positional_argument_duplicated_in_kwargs
(
self
):
msg
=
self
.
assertRaises
(
ValueError
,
self
.
api
.
testMethod
,
1
,
test_id
=
2
)
self
.
assertEqual
(
'Positional argument duplicated in kwargs: test_id'
,
msg
)
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