def get_competitive_pricing(self, marketplace_id, id_type, id_list, debug=None): """ Requests the competitive pricing for the specified marketplace products. *marketplace_id* (``str``) is the ID of the Amazon Marketplace the products belong to. *id_type* (``str``) is the type of ID used. This can only be "ASIN" or "SellerSKU". *id_list* (**sequence**) contains the ID (``str``) of each product to get. A maximum of 20 IDs can be requested at a single time. Returns the response XML (``str``). """ if not isinstance(marketplace_id, six.string_types): raise TypeError( "marketplace_id:{!r} is not a str.".format(marketplace_id)) elif not marketplace_id: raise ValueError( "marketplace_id:{!r} cannot be empty.".format(marketplace_id)) if not isinstance(id_type, six.string_types): raise TypeError("id_type:{!r} is not a str.".format(id_type)) elif not id_type: raise ValueError("id_type:{!r} cannot be empty.".format(id_type)) if not is_sequence(id_list): raise TypeError("id_list:{!r} is not a sequence.".format(id_list)) elif not id_list: raise ValueError("id_list:{!r} cannot be empty.".format(id_list)) elif len(id_list) > 20: raise ValueError( "id_list length:{} cannot be greater than 20.".format( len(id_list))) args = self.new_args() args['IdType'] = id_type if id_type == 'ASIN': args['Action'] = ACTIONS['get_competitive_pricing_for_asin'] args.update({ 'ASINList.ASIN.{}'.format(i): asin for i, asin in enumerate(id_list, 1) }) elif id_type == 'SellerSKU': args['Actions'] = ACTIONS['get_competitive_pricing_for_sku'] args.update({ 'SellerSKUList.SellerSKU.{}'.format(i): sku for i, sku in enumerate(id_list, 1) }) else: raise ValueError( "id_type:{!r} is not 'ASIN' or 'SellerSKU'.".format(id_type)) return self.send_request(args, path=self.path, debug=debug)
def submission_args(submissions, name=None): """ Converts the specified Feed Submission IDs into their resepctive URL query arguments. *submissions* (**sequence**) contains each Feed Submission ID (``str``). *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*submission_id* ``tuple``. - *key* (``str``) is the query argument key for *submission_id*. - *submission_id* (``str``) is the Feed Submission ID. """ if not name: name = 'submissions' if not is_sequence(submissions): raise TypeError("{}:{!r} is not a sequence.".format(name, submissions)) args = [] for i, sub_id in enumerate(submissions): if not isinstance(sub_id, six.string_types): raise TypeError("{}[{}]:{!r} is not a string.".format( name, i, sub_id)) elif not sub_id: raise ValueError("{}[{}]:{!r} cannot be empty.".format( name, i, sub_id)) sub_id = encode_string(sub_id, 'ASCII', name="{}[{}]".format(name, i)) args.append(('FeedSubmissionIdList.Id.{}'.format(i + 1), sub_id)) return args
def request_args(requests, name=None): """ Converts the specified Report Request IDs into their respective URL query arguments. *requests* (**sequence**) contains each Report Request ID (``str``). *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*request_id* ``tuple``. - *key* (``str``) is the query argument key for *request_id*. - *request_id* (``str``) is the Report Request ID. """ if not name: name = 'requests' if not is_sequence(requests): raise TypeError("{}:{!r} is not a sequence.".format(name, requests)) args = [] for i, request_id in enumerate(requests, 0): if not isinstance(request_id, basestring): raise TypeError("{}[{}]:{!r} is not a string.".format(name, i, request_id)) elif not request_id: raise ValueError("{}[{}]:{!r} cannot be empty.".format(name, i, request_id)) request_id = encode_string(request_id, 'ASCII', name="{}[{}]".format(name, i)) args.append(('ReportRequestIdList.Id.{}'.format(i + 1), request_id)) return args
def feed_type_args(feed_types, name=None): """ Converts the specified Feed Types into their resepctive URL query arguments. *feed_types* (**sequence**) contains each Feed Type (``str``). This can contain any of the keys or values from ``FEED_TYPES``. *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*feed_type* ``tuple``. - *key* (``str``) is the query argument key for *feed_type*. - *feed_type* (``str``) is the Feed Type ID. """ if not name: name = 'feed_types' if not is_sequence(feed_types): raise TypeError("{}:{!r} is not a sequence.".format(name, feed_types)) args = [] for i, feed_type in enumerate(feed_types): feed_type = FEED_TYPES.get(feed_type, feed_type) if not isinstance(feed_type, str): raise TypeError("{}[{}]:{!r} is not a str.".format(name, i, feed_type)) elif not feed_type: raise ValueError("{}[{}]:{!r} cannot be empty.".format(name, i, feed_type)) feed_type = encode_string(feed_type, 'ASCII', name="{}[{}]".format(name, i)) args.append(('FeedTypeList.Type.{}'.format(i + 1), feed_type)) return args
def report_type_args(report_types, name=None): """ Converts the specified Report Types into their respective URL query arguments. *report_types* (**sequence**) contains each Report Type (``str``). This can contain any keys or values from ``REPORT_TYPES``. *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*report_type* ``tuple``. - *key* (``str``) is the query argument key for *report_type*. - *report_type* (``str``) is the Report Type. """ if not name: name = 'report_types' if not is_sequence(report_types): raise TypeError("{}:{!r} is not a sequence.".format(name, report_types)) args = [] for i, report_type in enumerate(report_types, 0): report_type = REPORT_TYPES.get(report_type, report_type) if not isinstance(report_type, basestring): raise TypeError("{}[{}]:{!r} is not a string.".format(name, i, report_type)) elif not report_type: raise ValueError("{}[{}]:{!r} cannot be empty.".format(name, i, report_type)) report_type = encode_string(report_type, 'ASCII', name="{}[{}]".format(name, i)) args.append(('ReportTypeList.Type.{}'.format(i + 1), report_type)) return args
def update_report_acknowledgements(self, reports, marketplaces=None, debug=None): """ Updates the acknowledged status of the specified Reports. *reports* (**sequence**) is the list of Report IDs (``int``) to update. The maximum number of Reports that can be specified is 100. *marketplaces* (**sequence**) is the list of Amazon Marketplace IDs (``str``). Default is ``None`` for all marketplaces. """ if not is_sequence(reports): raise TypeError("reports:{!r} is not a sequence.".format(reports)) elif len(reports) < 0 or 100 < len(reports): raise ValueError("reports len:{!r} must be between 1 and 100 inclusive.".format(len(reports))) # Build args. args = self.new_args() args['Action'] = 'UpdateReportAcknowledgements' args['Acknowledged'] = 'true' for i, report_id in enumerate(reports, 0): if not isinstance(report_id, basestring): raise TypeError("reports[{}]:{!r} is not a string.".format(i, report_id)) elif not report_id: raise ValueError("reports[{}]:{!r} cannot be empty.".format(i, report_id)) report_id = encode_string(report_id, 'ASCII', name="reports[{}]".format(i)) args['ReportIdList.Id.{}'.format(report_id)] = report_id if marketplaces is not None: args.update(marketplace_args(marketplaces, name='marketplaces')) # Send Request. return self.send_request(args, debug=debug)
def status_args(statuses, name=None): """ Converts the specified Feed Processing Statuses into their respective URL query arguments. *statuses* (**sequence**) contains each Feed Processing Status (``str``). This can contain any of the keys or value from ``PROCESSING_STATUSES``. *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*status* ``tuple``. - *key* (``str``) is the query argument key for *status*. - *status* (``str``) is the Feed Processing Status. """ if not name: name = 'statuses' if not is_sequence(statuses): raise TypeError("{}:{!r} is not a sequence.".format(name, statuses)) args = [] for i, status in enumerate(statuses): status = PROCESSING_STATUSES.get(status, status) if not isinstance(status, str): raise TypeError("{}[{}]:{!r} is not a str.".format(name, i, status)) elif not status: raise ValueError("{}[{}]:{!r} cannot be empty.".format(name, i, status)) status = encode_string(status, 'ASCII', name="{}[{}]".format(name, i)) args.append(('FeedProcessingStatusList.Status.{}'.format(i + 1), status)) return args
def submission_args(submissions, name=None): """ Converts the specified Feed Submission IDs into their resepctive URL query arguments. *submissions* (**sequence**) contains each Feed Submission ID (``str``). *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*submission_id* ``tuple``. - *key* (``str``) is the query argument key for *submission_id*. - *submission_id* (``str``) is the Feed Submission ID. """ if not name: name = 'submissions' if not is_sequence(submissions): raise TypeError("{}:{!r} is not a sequence.".format(name, submissions)) args = [] for i, sub_id in enumerate(submissions): if not isinstance(sub_id, basestring): raise TypeError("{}[{}]:{!r} is not a string.".format(name, i, sub_id)) elif not sub_id: raise ValueError("{}[{}]:{!r} cannot be empty.".format(name, i, sub_id)) sub_id = encode_string(sub_id, 'ASCII', name="{}[{}]".format(name, i)) args.append(('FeedSubmissionIdList.Id.{}'.format(i + 1), sub_id)) return args
def get_my_price(self, marketplace_id, id_type, id_list, condition=None, verbose=None): """ Requests the seller's price for the specified marketplace products. *marketplace_id* (``str``) is the ID of the Amazon Marketplace the products belong to. *id_type* (``str``) is the type of ID used. This can only be "ASIN" or "SellerSKU". *id_list* (**sequence**) contains the ID (``str``) of each product to get. A maximum of 20 IDs can be requested at a single time. *condition* (``str``) optionally filters the returned listings to be based upon item condition. This can be any key or value from ``ITEM_CONDITIONS``. Default is ``None`` for no filter. Returns the response XML (``str``). """ if not isinstance(marketplace_id, str): raise TypeError("marketplace_id:{!r} is not a str.".format(marketplace_id)) elif not marketplace_id: raise ValueError("marketplace_id:{!r} cannot be empty.".format(marketplace_id)) if not isinstance(id_type, str): raise TypeError("id_type:{!r} is not a str.".format(id_type)) elif not id_type: raise ValueError("id_type:{!r} cannot be empty.".format(id_type)) if not is_sequence(id_list): raise TypeError("id_list:{!r} is not a sequence.".format(id_list)) elif not id_list: raise ValueError("id_list:{!r} cannot be empty.".format(id_list)) elif len(id_list) > 20: raise ValueError("id_list length:{} cannot be greater than 20.".format(len(id_list))) if condition is not None: condition = ITEM_CONDITIONS.get(condition, condition) if not isinstance(condition, str): raise TypeError("condition:{!r} is not a str.".format(condition)) elif not condition: raise ValueError("condition:{!r} cannot be empty.".format(condition)) args = self.new_args() args['IdType'] = id_type if id_type == 'ASIN': args['Action'] = ACTIONS['get_my_price_for_asin'] args.update({'ASINList.ASIN.{}'.format(i): asin for i, asin in enumerate(id_list, 1)}) elif id_type == 'SellerSKU': args['Actions'] = ACTIONS['get_my_price_for_sku'] args.update({'SellerSKUList.SellerSKU.{}'.format(i): sku for i, sku in enumerate(id_list, 1)}) else: raise ValueError("id_type:{!r} is not 'ASIN' or 'SellerSKU'.".format(id_type)) if condition is not None: args['ItemCondition'] = condition return self.send_request(args, path=self.path, verbose=verbose)
def get_my_price(self, marketplace_id, id_type, id_list, condition=None, verbose=None): """ Requests the seller's price for the specified marketplace products. *marketplace_id* (``str``) is the ID of the Amazon Marketplace the products belong to. *id_type* (``str``) is the type of ID used. This can only be "ASIN" or "SellerSKU". *id_list* (**sequence**) contains the ID (``str``) of each product to get. A maximum of 20 IDs can be requested at a single time. *condition* (``str``) optionally filters the returned listings to be based upon item condition. This can be any key or value from ``ITEM_CONDITIONS``. Default is ``None`` for no filter. Returns the response XML (``str``). """ if not isinstance(marketplace_id, six.string_types): raise TypeError("marketplace_id:{!r} is not a str.".format(marketplace_id)) elif not marketplace_id: raise ValueError("marketplace_id:{!r} cannot be empty.".format(marketplace_id)) if not isinstance(id_type, six.string_types): raise TypeError("id_type:{!r} is not a str.".format(id_type)) elif not id_type: raise ValueError("id_type:{!r} cannot be empty.".format(id_type)) if not is_sequence(id_list): raise TypeError("id_list:{!r} is not a sequence.".format(id_list)) elif not id_list: raise ValueError("id_list:{!r} cannot be empty.".format(id_list)) elif len(id_list) > 20: raise ValueError("id_list length:{} cannot be greater than 20.".format(len(id_list))) if condition is not None: condition = ITEM_CONDITIONS.get(condition, condition) if not isinstance(condition, six.string_types): raise TypeError("condition:{!r} is not a str.".format(condition)) elif not condition: raise ValueError("condition:{!r} cannot be empty.".format(condition)) args = self.new_args() args['IdType'] = id_type if id_type == 'ASIN': args['Action'] = ACTIONS['get_my_price_for_asin'] args.update({'ASINList.ASIN.{}'.format(i): asin for i, asin in enumerate(id_list, 1)}) elif id_type == 'SellerSKU': args['Actions'] = ACTIONS['get_my_price_for_sku'] args.update({'SellerSKUList.SellerSKU.{}'.format(i): sku for i, sku in enumerate(id_list, 1)}) else: raise ValueError("id_type:{!r} is not 'ASIN' or 'SellerSKU'.".format(id_type)) if condition is not None: args['ItemCondition'] = condition return self.send_request(args, path=self.path, verbose=verbose)
def update_report_acknowledgements(self, reports, acknowledged=None, marketplaces=None, debug=None): """ Updates the acknowledged status of the specified Reports. *reports* (**sequence**) is the list of Report IDs (``int``) to update. The maximum number of Reports that can be specified is 100. *acknowledged* (**boolean**) is whether or not to mark the reports passed as acknowledged. Default is ``None``. Amazon MWS treats the absense of acknowledged by defaulting the value to True. *marketplaces* (**sequence**) is the list of Amazon Marketplace IDs (``str``). Default is ``None`` for all marketplaces. """ if not is_sequence(reports): raise TypeError("reports:{!r} is not a sequence.".format(reports)) elif len(reports) < 0 or 100 < len(reports): raise ValueError( "reports len:{!r} must be between 1 and 100 inclusive.".format( len(reports))) # Build args. args = self.new_args() args['Action'] = 'UpdateReportAcknowledgements' if acknowledged is True: args['Acknowledged'] = 'true' elif acknowledged is False: args['Acknowledged'] = 'false' elif acknowledged is not None: raise TypeError( "reports['acknowledged']:{!r} is not boolean.".format( acknowledged)) for i, report_id in enumerate(reports, 1): if not isinstance(report_id, basestring): raise TypeError("reports[{}]:{!r} is not a string.".format( i, report_id)) elif not report_id: raise ValueError("reports[{}]:{!r} cannot be empty.".format( i, report_id)) report_id = encode_string(report_id, 'ASCII', name="reports[{}]".format(i)) args['ReportIdList.Id.{}'.format(i)] = report_id if marketplaces is not None: args.update(marketplace_args(marketplaces, name='marketplaces')) # Send Request. return self.send_request(args, debug=debug)
def get_products(self, marketplace_id, id_type, id_list, debug=None): """ Requests the information for the specified marketplace products. *marketplace_id* (``str``) is the ID of the Amazon Marketplace the products are coming from. *id_type* (``str``) is the type of ID used. This can be only of the types listed under ``ID_TYPES``. *id_list* (**sequence**) contains the ID (``str``) of each product to get. A maximum of 10 ASINs, or 5 IDs of another type can be requested at a single time. Returns the response XML (``str``). """ if not isinstance(marketplace_id, six.string_types): raise TypeError( "marketplace_id:{!r} is not a str.".format(marketplace_id)) elif not marketplace_id: raise ValueError( "marketplace_id:{!r} cannot be empty.".format(marketplace_id)) if not isinstance(id_type, six.string_types): raise TypeError("id_type:{!r} is not a str.".format(id_type)) elif not id_type: raise ValueError("id_type:{!r} cannot be empty.".format(id_type)) if not is_sequence(id_list): raise TypeError("id_list:{!r} is not a sequence.".format(id_list)) elif not id_list: raise ValueError("id_list:{!r} cannot be empty.".format(id_list)) if len(id_list) > 5: raise ValueError( "id_list length:{} cannot be greater than 5.".format( len(id_list))) args = self.new_args() if id_type == 'ASIN': args['Action'] = ACTIONS['get_products'] args.update({ 'ASINList.ASIN.{}'.format(i): asin for i, asin in enumerate(id_list, 1) }) else: args['IdType'] = id_type args['Action'] = ACTIONS['get_products_for_id'] args.update({ 'IDList.ID.{}'.format(i): id_ for i, id_ in enumerate(id_list, 1) }) return self.send_request(args, path=self.path, debug=debug)
def get_competitive_pricing(self, marketplace_id, id_type, id_list, verbose=None): """ Requests the competitive pricing for the specified marketplace products. *marketplace_id* (``str``) is the ID of the Amazon Marketplace the products belong to. *id_type* (``str``) is the type of ID used. This can only be "ASIN" or "SellerSKU". *id_list* (**sequence**) contains the ID (``str``) of each product to get. A maximum of 20 IDs can be requested at a single time. Returns the response XML (``str``). """ if not isinstance(marketplace_id, six.string_types): raise TypeError("marketplace_id:{!r} is not a str.".format(marketplace_id)) elif not marketplace_id: raise ValueError("marketplace_id:{!r} cannot be empty.".format(marketplace_id)) if not isinstance(id_type, six.string_types): raise TypeError("id_type:{!r} is not a str.".format(id_type)) elif not id_type: raise ValueError("id_type:{!r} cannot be empty.".format(id_type)) if not is_sequence(id_list): raise TypeError("id_list:{!r} is not a sequence.".format(id_list)) elif not id_list: raise ValueError("id_list:{!r} cannot be empty.".format(id_list)) elif len(id_list) > 20: raise ValueError("id_list length:{} cannot be greater than 20.".format(len(id_list))) args = self.new_args() args['IdType'] = id_type if id_type == 'ASIN': args['Action'] = ACTIONS['get_competitive_pricing_for_asin'] args.update({'ASINList.ASIN.{}'.format(i): asin for i, asin in enumerate(id_list, 1)}) elif id_type == 'SellerSKU': args['Actions'] = ACTIONS['get_competitive_pricing_for_sku'] args.update({'SellerSKUList.SellerSKU.{}'.format(i): sku for i, sku in enumerate(id_list, 1)}) else: raise ValueError("id_type:{!r} is not 'ASIN' or 'SellerSKU'.".format(id_type)) return self.send_request(args, path=self.path, verbose=verbose)
def update_report_acknowledgements(self, reports, acknowledged=None, marketplaces=None, debug=None): """ Updates the acknowledged status of the specified Reports. *reports* (**sequence**) is the list of Report IDs (``int``) to update. The maximum number of Reports that can be specified is 100. *acknowledged* (**boolean**) is whether or not to mark the reports passed as acknowledged. Default is ``None``. Amazon MWS treats the absense of acknowledged by defaulting the value to True. *marketplaces* (**sequence**) is the list of Amazon Marketplace IDs (``str``). Default is ``None`` for all marketplaces. """ if not is_sequence(reports): raise TypeError("reports:{!r} is not a sequence.".format(reports)) elif len(reports) < 0 or 100 < len(reports): raise ValueError("reports len:{!r} must be between 1 and 100 inclusive.".format(len(reports))) # Build args. args = self.new_args() args['Action'] = 'UpdateReportAcknowledgements' if acknowledged is True: args['Acknowledged'] = 'true' elif acknowledged is False: args['Acknowledged'] = 'false' elif acknowledged is not None: raise TypeError("reports['acknowledged']:{!r} is not boolean.".format(acknowledged)) for i, report_id in enumerate(reports, 1): if not isinstance(report_id, six.string_types): raise TypeError("reports[{}]:{!r} is not a string.".format(i, report_id)) elif not report_id: raise ValueError("reports[{}]:{!r} cannot be empty.".format(i, report_id)) report_id = encode_string(report_id, 'ASCII', name="reports[{}]".format(i)) args['ReportIdList.Id.{}'.format(i)] = report_id if marketplaces is not None: args.update(marketplace_args(marketplaces, name='marketplaces')) # Send Request. return self.send_request(args, debug=debug)
def get_products(self, marketplace_id, id_type, id_list, debug=None): """ Requests the information for the specified marketplace products. *marketplace_id* (``str``) is the ID of the Amazon Marketplace the products are coming from. *id_type* (``str``) is the type of ID used. This can be only of the types listed under ``ID_TYPES``. *id_list* (**sequence**) contains the ID (``str``) of each product to get. A maximum of 10 ASINs, or 5 IDs of another type can be requested at a single time. Returns the response XML (``str``). """ if not isinstance(marketplace_id, six.string_types): raise TypeError("marketplace_id:{!r} is not a str.".format(marketplace_id)) elif not marketplace_id: raise ValueError("marketplace_id:{!r} cannot be empty.".format(marketplace_id)) if not isinstance(id_type, six.string_types): raise TypeError("id_type:{!r} is not a str.".format(id_type)) elif not id_type: raise ValueError("id_type:{!r} cannot be empty.".format(id_type)) if not is_sequence(id_list): raise TypeError("id_list:{!r} is not a sequence.".format(id_list)) elif not id_list: raise ValueError("id_list:{!r} cannot be empty.".format(id_list)) if len(id_list) > 5: raise ValueError("id_list length:{} cannot be greater than 5.".format(len(id_list))) args = self.new_args() if id_type == 'ASIN': args['Action'] = ACTIONS['get_products'] args.update({'ASINList.ASIN.{}'.format(i): asin for i, asin in enumerate(id_list, 1)}) else: args['IdType'] = id_type args['Action'] = ACTIONS['get_products_for_id'] args.update({'IDList.ID.{}'.format(i): id_ for i, id_ in enumerate(id_list, 1)}) return self.send_request(args, path=self.path, debug=debug)
def report_type_args(report_types, name=None): """ Converts the specified Report Types into their respective URL query arguments. *report_types* (**sequence**) contains each Report Type (``str``). This can contain any keys or values from ``REPORT_TYPES``. *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*report_type* ``tuple``. - *key* (``str``) is the query argument key for *report_type*. - *report_type* (``str``) is the Report Type. """ if not name: name = 'report_types' if not is_sequence(report_types): raise TypeError("{}:{!r} is not a sequence.".format( name, report_types)) args = [] for i, report_type in enumerate(report_types, 0): report_type = REPORT_TYPES.get(report_type, report_type) if not isinstance(report_type, basestring): raise TypeError("{}[{}]:{!r} is not a string.".format( name, i, report_type)) elif not report_type: raise ValueError("{}[{}]:{!r} cannot be empty.".format( name, i, report_type)) report_type = encode_string(report_type, 'ASCII', name="{}[{}]".format(name, i)) args.append(('ReportTypeList.Type.{}'.format(i + 1), report_type)) return args
def feed_type_args(feed_types, name=None): """ Converts the specified Feed Types into their resepctive URL query arguments. *feed_types* (**sequence**) contains each Feed Type (``str``). This can contain any of the keys or values from ``FEED_TYPES``. *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*feed_type* ``tuple``. - *key* (``str``) is the query argument key for *feed_type*. - *feed_type* (``str``) is the Feed Type ID. """ if not name: name = 'feed_types' if not is_sequence(feed_types): raise TypeError("{}:{!r} is not a sequence.".format(name, feed_types)) args = [] for i, feed_type in enumerate(feed_types): feed_type = FEED_TYPES.get(feed_type, feed_type) if not isinstance(feed_type, six.string_types): raise TypeError("{}[{}]:{!r} is not a str.".format( name, i, feed_type)) elif not feed_type: raise ValueError("{}[{}]:{!r} cannot be empty.".format( name, i, feed_type)) feed_type = encode_string(feed_type, 'ASCII', name="{}[{}]".format(name, i)) args.append(('FeedTypeList.Type.{}'.format(i + 1), feed_type)) return args
def status_args(statuses, name=None): """ Converts the specified Feed Processing Statuses into their respective URL query arguments. *statuses* (**sequence**) contains each Feed Processing Status (``str``). This can contain any of the keys or value from ``PROCESSING_STATUSES``. *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*status* ``tuple``. - *key* (``str``) is the query argument key for *status*. - *status* (``str``) is the Feed Processing Status. """ if not name: name = 'statuses' if not is_sequence(statuses): raise TypeError("{}:{!r} is not a sequence.".format(name, statuses)) args = [] for i, status in enumerate(statuses): status = PROCESSING_STATUSES.get(status, status) if not isinstance(status, six.string_types): raise TypeError("{}[{}]:{!r} is not a str.".format( name, i, status)) elif not status: raise ValueError("{}[{}]:{!r} cannot be empty.".format( name, i, status)) status = encode_string(status, 'ASCII', name="{}[{}]".format(name, i)) args.append( ('FeedProcessingStatusList.Status.{}'.format(i + 1), status)) return args
def status_args(statuses, name=None): """ Converts the specified Report Processing Status into their respective URL query arguments. *statuses* (**sequence**) contains each Report Processing Status (``str``). This contain any keys or values from ``REPORT_STATUSES``. *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*status* ``tuple``. - *key* (``str``) is the query argument key for *status*. - *request_id* (``str``) is the Report Processing Status. """ if not name: name = 'statuses' if not is_sequence(statuses): raise TypeError("{}:{!r} is not a statuses.".format(name, statuses)) args = [] for i, status in enumerate(statuses, 0): if not isinstance(status, basestring): raise TypeError("{}[{}]:{!r} is not a string.".format( name, i, status)) elif not status: raise ValueError("{}[{}]:{!r} cannot be empty.".format( name, i, status)) status = encode_string(status, 'ASCII', name="{}[{}]".format(name, i)) args.append( ('ReportProcessingStatusList.Status.{}'.format(i + 1), status)) return args
def request_args(requests, name=None): """ Converts the specified Report Request IDs into their respective URL query arguments. *requests* (**sequence**) contains each Report Request ID (``str``). *name* (``str``) is the name to use when an error occurs. Returns a ``list`` containing each *key*-*request_id* ``tuple``. - *key* (``str``) is the query argument key for *request_id*. - *request_id* (``str``) is the Report Request ID. """ if not name: name = 'requests' if not is_sequence(requests): raise TypeError("{}:{!r} is not a sequence.".format(name, requests)) args = [] for i, request_id in enumerate(requests, 0): if not isinstance(request_id, basestring): raise TypeError("{}[{}]:{!r} is not a string.".format( name, i, request_id)) elif not request_id: raise ValueError("{}[{}]:{!r} cannot be empty.".format( name, i, request_id)) request_id = encode_string(request_id, 'ASCII', name="{}[{}]".format(name, i)) args.append(('ReportRequestIdList.Id.{}'.format(i + 1), request_id)) return args
def build_request(self, mws, path, args, body, content_type, debug=None): """ Builds the request. .. NOTE:: This should not be called directly. Use *self.request()*. *mws* (``MWS``) is the MWS instance. *path* (``str``) is the request path. *args* contains the query parameters. *body* (``str`` or ``file``) contains the body of the request. This can be ``None``. *content_type* (``str``) is the content type of *body*. *debug* (``dict``) is whether debugging information should be printed. Default is ``None`` for no debugging. - *body* (``bool``) is whether the request body should be printed (``True``), or not (``False``). Default is ``None`` for ``False``. - *info* (``bool``) is whether the request args and headers should be printed (``True``), or not (``False``). - *url* (``bool``) is whether the generated URL should be printed (``True``), or not (``False``). Default is ``None`` for ``False``. Returns a ``tuple`` containing: *method*, the request URL (``str``), the request headers (``dict`` or ``None``), and the request body (``str``, ``file`` or ``None``). """ # Before anything else, ensure body is proper data type (if string) if body is not None: if isinstance(body, six.string_types): # Ensure string types are byte-arrays. body = six.b(body) if debug is None: debug = {} if not isinstance(mws, MWS): raise TypeError("mws:{!r} is not an MWS.".format(mws)) if isinstance(args, dict): args = list(six.iteritems(args)) elif is_sequence(args): args = args[:] else: raise TypeError( "args:{!r} must be a dict or sequence.".format(args)) # Check for missing and reserved args. arg_keys = set([k for k, _v in args]) missing = self.req_args_required - arg_keys if len(missing) > 1: raise KeyError("args:{!r} is missing keys: {}.".format( args, ", ".join(map(repr, missing)))) elif missing: raise KeyError("args:{!r} is missing key: {!r}.".format( args, missing.pop())) reserved = self.req_args_sig & arg_keys if len(reserved) > 1: raise KeyError("args:{!r} cannot have keys: {}.".format( args, ", ".join(map(repr, reserved)))) elif reserved: raise KeyError("args:{!r} cannot have key: {!r}.".format( args, reserved.pop())) if body is not None: body_is_str = isinstance(body, six.binary_type) body_is_file = callable(getattr(body, 'read', None)) if not body_is_str and not body_is_file: raise TypeError("body:{!r} is not a str or file.".format(body)) if not isinstance(content_type, six.string_types): raise TypeError( "content_type:{!r} is not a str.".format(content_type)) elif not content_type: raise ValueError( "content_type:{!r} cannot be empty.".format(content_type)) if path is not None and not isinstance(path, six.string_types): raise TypeError("path:{!r} is not a str.".format(path)) # Query. args += [('SignatureMethod', SIGNATURE_METHODS[self.sig_method]), ('SignatureVersion', self.sig_version)] args = sorted(args, key=self.sort_args_key) query = "&".join(("{}={}".format( six.moves.urllib.parse.quote(str(k), self.req_args_safe_chars), six.moves.urllib.parse.quote(str(v), self.req_args_safe_chars))) for k, vals in args for v in (vals if is_sequence(vals) else [vals])) # Signature method = "GET" if body is None else "POST" result = six.moves.urllib.parse.urlparse(mws.endpoint) domain = result.netloc or result.path path = six.moves.urllib.parse.quote( os.path.normpath('/' + path.lstrip('/'))) if path else "/" sig = self.sign_request(mws.secret_key, method, domain, path, query) # URL. url = "{host}{path}?{query}&Signature={sig}".format( host=mws.endpoint, path=path, query=query, sig=six.moves.urllib.parse.quote(sig, safe='/')) # Headers. headers = {'User-Agent': mws.user_agent} if body is not None: if body_is_str: body_len = len(body) body_md5 = base64.b64encode(hashlib.md5(body).digest()) elif body_is_file: if callable(getattr(body, 'seek', None)) and callable( getattr(body, 'tell', None)): # MD5 body and get length. pos = body.tell() md5 = hashlib.md5() while True: chunk = body.read(2**16) if not chunk: break md5.update(chunk) body_len = body.tell() - pos body_md5 = base64.b64encode(md5.digest()) body.seek(pos, os.SEEK_SET) else: body = body.read() body_len = len(body) body_md5 = base64.b64encode(hashlib.md5(body).digest()) body_is_file = False if body_len > mws.max_size: raise ValueError( "body length:{!r} cannot be greater than {}.".format( body_len, mws.max_size)) headers['Content-Type'] = content_type headers['Content-Length'] = body_len headers['Content-MD5'] = body_md5 else: body_len = None # Debug info. if debug: if debug.get('url', False): print("URL ({}:{})".format(url.__class__.__name__, len(url))) print("--------") print(url) print("--------") if debug.get('info', False): print("Args ({})".format(len(args))) print("---------") pprint.pprint(args) print("---------") print("Headers ({})".format(len(headers))) print("------------") pprint.pprint(headers) print("------------") if debug.get('body', False) or debug.get('info', False): print("Body ({}:{})".format(body.__class__.__name__, body_len)) if debug.get('body', False): print("-" * 20) if body_is_file: pos = body.tell() print(body.read()) body.seek(pos, os.SEEK_SET) else: print(body) print("-" * 20) return method, url, headers, body
def list_orders(self, created_after=None, updated_after=None, order_statuses=None, marketplaces=None): """ Requests the list of Orders that match the specified criteria. Either *created_after* or *updated_after* must be set, but not both. *created_after* (``datetime.datetime`` or ``float``) is used to select orders that were created at/after the specified date-time. *updated_after* (``datetime.datetime`` or ``float``) is used to select orders that were updated at/after the specified date-time. The query can be further refined by specifying any of the following: *order_statuses* (**sequence**) contains each Order Status (``str``) to filter the list of orders to list. Default is ``None`` for all Order Statuses. .. SEEALSO:: ``ORDER_STATUSES``. *marketplaces* (**sequence**) contains the ID (``str``) of each Amazon Marketplace to list orders from. Default is ``None`` for all Amazon Marketplaces. Returns the response XML (``str``). """ if (created_after is None and updated_after is None) or (created_after is not None and updated_after is not None): raise ValueError("Either created_after:{!r} or updated_after:{!r} must be set, but not both.".format(created_after, updated_after)) args = self.new_args() if created_after is not None: args['CreatedAfter'] = datetime_to_iso8601(created_after, name='created_after') if updated_after is not None: args['LastUpdatedAfter'] = datetime_to_iso8601(updated_after, name='updated_after') if order_statuses is not None: if not is_sequence(order_statuses): raise TypeError("order_statuses:{!r} is not a sequence.".format(order_statuses)) elif not order_statuses: raise ValueError("order_statuses:{!r} cannot be empty.".format(order_statuses)) amazon_statuses = [] for i, status in enumerate(order_statuses): status = ORDER_STATUSES.get(status, status) if not isinstance(status, basestring): raise TypeError("order_statuses[{}]:{!r} is not a string.".format(i, status)) elif not status: raise ValueError("order_statuses[{}]:{!r} cannot be empty.".format(i, status)) try: status = status.encode('ASCII') except UnicodeDecodeError as e: e.reason += " for order_statuses[{}]".format(i) e.args = e.args[:4] + (e.reason,) raise e amazon_statuses.append(status) args['OrderStatus'] = amazon_statuses if marketplaces is not None: if not is_sequence(marketplaces): raise TypeError("marketplaces:{!r} is not a sequence.".format(marketplaces)) elif not marketplaces: raise ValueError("marketplaces:{!r} cannot be empty.".format(marketplaces)) for i, market in enumerate(marketplaces): if not isinstance(market, basestring): raise TypeError("marketplaces[{}]:{!r} is not a string.".format(i, market)) elif not market: raise ValueError("marketplaces[{}]:{!r} cannot be empty.".format(i, market)) try: market = market.encode('ASCII') except UnicodeDecodeError as e: e.reason += " for marketplaces[{}]".format(i) e.args = e.args[:4] + (e.reason,) raise e args['MarketplaceId'] = marketplaces return self.send_request('ListOrders', args)
def build_request(self, mws, path, args, body, content_type, debug=None): """ Builds the request. .. NOTE:: This should not be called directly. Use *self.request()*. *mws* (``MWS``) is the MWS instance. *path* (``str``) is the request path. *args* contains the query parameters. *body* (``str`` or ``file``) contains the body of the request. This can be ``None``. *content_type* (``str``) is the content type of *body*. *debug* (``dict``) is whether debugging information should be printed. Default is ``None`` for no debugging. - *body* (``bool``) is whether the request body should be printed (``True``), or not (``False``). Default is ``None`` for ``False``. - *info* (``bool``) is whether the request args and headers should be printed (``True``), or not (``False``). - *url* (``bool``) is whether the generated URL should be printed (``True``), or not (``False``). Default is ``None`` for ``False``. Returns a ``tuple`` containing: *method*, the request URL (``str``), the request headers (``dict`` or ``None``), and the request body (``str``, ``file`` or ``None``). """ # Before anything else, ensure body is proper data type (if string) if body is not None: if isinstance(body, six.string_types): # Ensure string types are byte-arrays. body = six.b(body) if debug is None: debug = {} if not isinstance(mws, MWS): raise TypeError("mws:{!r} is not an MWS.".format(mws)) if isinstance(args, dict): args = list(six.iteritems(args)) elif is_sequence(args): args = args[:] else: raise TypeError("args:{!r} must be a dict or sequence.".format(args)) # Check for missing and reserved args. arg_keys = set([k for k, _v in args]) missing = self.req_args_required - arg_keys if len(missing) > 1: raise KeyError("args:{!r} is missing keys: {}.".format(args, ", ".join(map(repr, missing)))) elif missing: raise KeyError("args:{!r} is missing key: {!r}.".format(args, missing.pop())) reserved = self.req_args_sig & arg_keys if len(reserved) > 1: raise KeyError("args:{!r} cannot have keys: {}.".format(args, ", ".join(map(repr, reserved)))) elif reserved: raise KeyError("args:{!r} cannot have key: {!r}.".format(args, reserved.pop())) if body is not None: body_is_str = isinstance(body, six.binary_type) body_is_file = callable(getattr(body, 'read', None)) if not body_is_str and not body_is_file: raise TypeError("body:{!r} is not a str or file.".format(body)) if not isinstance(content_type, six.string_types): raise TypeError("content_type:{!r} is not a str.".format(content_type)) elif not content_type: raise ValueError("content_type:{!r} cannot be empty.".format(content_type)) if path is not None and not isinstance(path, six.string_types): raise TypeError("path:{!r} is not a str.".format(path)) # Query. args += [ ('SignatureMethod', SIGNATURE_METHODS[self.sig_method]), ('SignatureVersion', self.sig_version) ] args = sorted(args, key=self.sort_args_key) query = "&".join(( "{}={}".format(six.moves.urllib.parse.quote(str(k), self.req_args_safe_chars), six.moves.urllib.parse.quote(str(v), self.req_args_safe_chars)) ) for k, vals in args for v in (vals if is_sequence(vals) else [vals])) # Signature method = "GET" if body is None else "POST" result = six.moves.urllib.parse.urlparse(mws.endpoint) domain = result.netloc or result.path path = six.moves.urllib.parse.quote(os.path.normpath('/' + path.lstrip('/'))) if path else "/" sig = self.sign_request(mws.secret_key, method, domain, path, query) # URL. url = "{host}{path}?{query}&Signature={sig}".format( host=mws.endpoint, path=path, query=query, sig=six.moves.urllib.parse.quote(sig, safe='/') ) # Headers. headers = { 'User-Agent': mws.user_agent } if body is not None: if body_is_str: body_len = len(body) body_md5 = base64.b64encode(hashlib.md5(body).digest()) elif body_is_file: if callable(getattr(body, 'seek', None)) and callable(getattr(body, 'tell', None)): # MD5 body and get length. pos = body.tell() md5 = hashlib.md5() while True: chunk = body.read(2**16) if not chunk: break md5.update(chunk) body_len = body.tell() - pos body_md5 = base64.b64encode(md5.digest()) body.seek(pos, os.SEEK_SET) else: body = body.read() body_len = len(body) body_md5 = base64.b64encode(hashlib.md5(body).digest()) body_is_file = False if body_len > mws.max_size: raise ValueError("body length:{!r} cannot be greater than {}.".format(body_len, mws.max_size)) headers['Content-Type'] = content_type headers['Content-Length'] = body_len headers['Content-MD5'] = body_md5 # Debug info. if debug: if debug.get('url', False): print("URL ({}:{})".format(url.__class__.__name__, len(url))) print("--------") print(url) print("--------") if debug.get('info', False): print("Args ({})".format(len(args))) print("---------") pprint.pprint(args) print("---------") print("Headers ({})".format(len(headers))) print("------------") pprint.pprint(headers) print("------------") if debug.get('body', False) or debug.get('info', False): print("Body ({}:{})".format(body.__class__.__name__, body_len)) if debug.get('body', False): print("-"*20) if body_is_file: pos = body.tell() print(body.read()) body.seek(pos, os.SEEK_SET) else: print(body) print("-"*20) return method, url, headers, body