Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

fix broken mws.iter_call() and mws.iter_response() #1374

Closed
wants to merge 1 commit into from

2 participants

@disruptek

My ugly hack broke (as it was bound to) due to auth changes elsewhere. This fixes the convenience methods; generators that yield responses as appropriate when an arbitrary call result is paginated.

@toastdriven toastdriven commented on the diff
boto/mws/connection.py
((12 lines not shown))
}
content_md5 = lambda c: base64.encodestring(hashlib.md5(c).digest()).strip()
decorated_attrs = ('action', 'response', 'section',
'quota', 'restore', 'version')
+api_call_map = {}

I'm not in love with this being module-level (think very long-lived processes caching this indefinitely), but I don't know if there's a better place to be putting it.

Actually, that's why I put it there. If you come up with a better idea, I'll listen...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@toastdriven

I'd feel a ton better about this change if there were some tests backing it. Since it looks like most of this can be faked, just adding a couple simple unit (non-integration) tests for the wrapper & method_for functions would be perfect. I like it much better than the previous solution.

@disruptek

If a couple simple unit tests for these methods make you feel a ton better, I encourage you to submit a pull request. :-)

I feel a ton better about replacing code that doesn't work at all and isn't covered by tests with code that works fine and isn't covered by tests.

@disruptek

How are the tests coming?

@toastdriven toastdriven was assigned
@toastdriven toastdriven referenced this pull request from a commit in toastdriven/boto
@toastdriven toastdriven Added tests for the changes to MWS in #1374. 9e51f32
@toastdriven toastdriven referenced this pull request
Merged

MWS Iter fix #1804

@toastdriven

Merged. Thanks for the patch!

@mkolodny mkolodny referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@toastdriven toastdriven removed their assignment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 7, 2013
  1. simplify method_for(), fixing collision with auth/_get_region_name

    Andy Davidoff authored
    tighten PEP8
This page is out of date. Refresh to see the latest.
Showing with 25 additions and 25 deletions.
  1. +25 −25 boto/mws/connection.py
View
50 boto/mws/connection.py
@@ -37,15 +37,16 @@
'Products': ('2011-10-01', 'SellerId', '/Products/2011-10-01'),
'Sellers': ('2011-07-01', 'SellerId', '/Sellers/2011-07-01'),
'Inbound': ('2010-10-01', 'SellerId',
- '/FulfillmentInboundShipment/2010-10-01'),
+ '/FulfillmentInboundShipment/2010-10-01'),
'Outbound': ('2010-10-01', 'SellerId',
- '/FulfillmentOutboundShipment/2010-10-01'),
+ '/FulfillmentOutboundShipment/2010-10-01'),
'Inventory': ('2010-10-01', 'SellerId',
- '/FulfillmentInventory/2010-10-01'),
+ '/FulfillmentInventory/2010-10-01'),
}
content_md5 = lambda c: base64.encodestring(hashlib.md5(c).digest()).strip()
decorated_attrs = ('action', 'response', 'section',
'quota', 'restore', 'version')
+api_call_map = {}

I'm not in love with this being module-level (think very long-lived processes caching this indefinitely), but I don't know if there's a better place to be putting it.

Actually, that's why I put it there. If you come up with a better idea, I'll listen...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
def add_attrs_from(func, to):
@@ -67,7 +68,7 @@ def wrapper(self, *args, **kw):
kw.pop(key)
return func(self, *args, **kw)
wrapper.__doc__ = "{0}\nLists: {1}".format(func.__doc__,
- ', '.join(fields))
+ ', '.join(fields))
return add_attrs_from(func, to=wrapper)
return decorator
@@ -101,7 +102,7 @@ def destructure_object(value, into={}, prefix=''):
destructure_object(attr, into=into, prefix=prefix + '.' + name)
elif filter(lambda x: isinstance(value, x), (list, set, tuple)):
for index, element in [(prefix + '.' + str(i + 1), value[i])
- for i in range(len(value))]:
+ for i in range(len(value))]:
destructure_object(element, into=into, prefix=index)
elif isinstance(value, bool):
into[prefix] = str(value).lower()
@@ -118,7 +119,7 @@ def wrapper(*args, **kw):
destructure_object(kw.pop(field), into=kw, prefix=field)
return func(*args, **kw)
wrapper.__doc__ = "{0}\nObjects: {1}".format(func.__doc__,
- ', '.join(fields))
+ ', '.join(fields))
return add_attrs_from(func, to=wrapper)
return decorator
@@ -137,7 +138,7 @@ def wrapper(*args, **kw):
return func(*args, **kw)
message = ' OR '.join(['+'.join(g) for g in groups])
wrapper.__doc__ = "{0}\nRequired: {1}".format(func.__doc__,
- message)
+ message)
return add_attrs_from(func, to=wrapper)
return decorator
@@ -156,7 +157,7 @@ def wrapper(*args, **kw):
return func(*args, **kw)
message = ' OR '.join(['+'.join(g) for g in groups])
wrapper.__doc__ = "{0}\nEither: {1}".format(func.__doc__,
- message)
+ message)
return add_attrs_from(func, to=wrapper)
return decorator
@@ -175,8 +176,8 @@ def wrapper(*args, **kw):
return func(*args, **kw)
message = ' OR '.join(['+'.join(g) for g in groups])
wrapper.__doc__ = "{0}\n{1} requires: {2}".format(func.__doc__,
- field,
- message)
+ field,
+ message)
return add_attrs_from(func, to=wrapper)
return decorator
@@ -192,7 +193,7 @@ def wrapper(*args, **kw):
raise KeyError(message)
return func(*args, **kw)
wrapper.__doc__ = "{0}\nSome Required: {1}".format(func.__doc__,
- ', '.join(fields))
+ ', '.join(fields))
return add_attrs_from(func, to=wrapper)
return decorator
@@ -206,7 +207,7 @@ def wrapper(*args, **kw):
kw[field] = str(kw[field]).lower()
return func(*args, **kw)
wrapper.__doc__ = "{0}\nBooleans: {1}".format(func.__doc__,
- ', '.join(fields))
+ ', '.join(fields))
return add_attrs_from(func, to=wrapper)
return decorator
@@ -237,6 +238,7 @@ def wrapper(self, *args, **kw):
wrapper.__doc__ = "MWS {0}/{1} API call; quota={2} restore={3:.2f}\n" \
"{4}".format(action, version, quota, restore,
func.__doc__)
+ api_call_map[action] = func.func_name
return wrapper
return decorator
@@ -260,7 +262,8 @@ def post_request(self, path, params, cls, body='', headers={}, isXML=True):
Modelled off of the inherited get_object/make_request flow.
"""
request = self.build_base_http_request('POST', path, None, data=body,
- params=params, headers=headers, host=self.server_name())
+ params=params, headers=headers,
+ host=self.server_name())
response = self._mexe(request, override_num_retries=None)
body = response.read()
boto.log.debug(body)
@@ -285,13 +288,10 @@ def method_for(self, name):
The named method can be in CamelCase or underlined_lower_case.
This is the complement to MWSConnection.any_call.action
"""
- # this looks ridiculous but it should be better than regex
action = '_' in name and string.capwords(name, '_') or name
- attribs = [getattr(self, m) for m in dir(self)]
- ismethod = lambda m: type(m) is type(self.method_for)
- ismatch = lambda m: getattr(m, 'action', None) == action
- method = filter(ismatch, filter(ismethod, attribs))
- return method and method[0] or None
+ if action in api_call_map:
+ return getattr(self, api_call_map[action])
+ return None
def iter_call(self, call, *args, **kw):
"""Pass a call name as the first argument and a generator
@@ -322,7 +322,7 @@ def submit_feed(self, path, response, headers={}, body='', **kw):
"""Uploads a feed for processing by Amazon MWS.
"""
return self.post_request(path, kw, response, body=body,
- headers=headers)
+ headers=headers)
@structured_lists('FeedSubmissionIdList.Id', 'FeedTypeList.Type',
'FeedProcessingStatusList.Status')
@@ -365,10 +365,10 @@ def get_feed_submission_result(self, path, response, **kw):
def get_service_status(self, **kw):
"""Instruct the user on how to get service status.
"""
+ sections = ', '.join(map(str.lower, api_version_path.keys()))
message = "Use {0}.get_(section)_service_status(), " \
"where (section) is one of the following: " \
- "{1}".format(self.__class__.__name__,
- ', '.join(map(str.lower, api_version_path.keys())))
+ "{1}".format(self.__class__.__name__, sections)
raise AttributeError(message)
@structured_lists('MarketplaceIdList.Id')
@@ -659,8 +659,8 @@ def list_orders(self, path, response, **kw):
frame that you specify.
"""
toggle = set(('FulfillmentChannel.Channel.1',
- 'OrderStatus.Status.1', 'PaymentMethod.1',
- 'LastUpdatedAfter', 'LastUpdatedBefore'))
+ 'OrderStatus.Status.1', 'PaymentMethod.1',
+ 'LastUpdatedAfter', 'LastUpdatedBefore'))
for do, dont in {
'BuyerEmail': toggle.union(['SellerOrderId']),
'SellerOrderId': toggle.union(['BuyerEmail']),
@@ -804,7 +804,7 @@ def list_marketplace_participations(self, path, response, **kw):
@requires(['NextToken'])
@api_action('Sellers', 15, 60)
def list_marketplace_participations_by_next_token(self, path, response,
- **kw):
+ **kw):
"""Returns the next page of marketplaces and participations
using the NextToken value that was returned by your
previous request to either ListMarketplaceParticipations
Something went wrong with that request. Please try again.