Giter Club home page Giter Club logo

python-amazon-mws's Introduction

slack CI Testing Coverage

python-amazon-mws

python-amazon-mws is a Python connector to Amazon Marketplace Web Services (or MWS). It provides a simple way to build and send requests to MWS, allowing access to all that MWS can do from your Python application.

Mostly inactive development

Time to maintain this project is limited at present, and the MWS service is being deprecated in favor of the newer Selling Partners API (SP-API).

If you require assistance with this package specifically, please feel free to open an issue. This project may be archived in the near future and development halted.

Installation

Two versions are currently available:

  • Installing mws from PyPI, you will have version 0.8.x, which is built from our master branch.
    • This is a close match to the original package by czpython, with some small tweaks to add critical functionality.
    • Supports Python 2.7 and 3.4+.
  • The updated 1.0devXY version must be installed from this repo's develop branch.
    • This includes additional API coverage that may be missing in 0.8.x, as well as other new features.
    • Some methods have new or updated arguments compared to 0.8.x, and much of the original monolithic mws module has been broken down into separate components (such as the mws.apis collection of modules).
    • Supports Python 3.6+.

Installing 0.8.x (PyPI)

Warning: If you are using version 0.8.x in a production system, note that our eventual 1.0 release will be backwards-incompatible, and may break programs that depend on the 0.8.x version. We advise users pin their Pip-installed version in requirements as mws~=0.8.9.

Install the mws package using Pip:

pip install mws

Alternatively, you can install direct from this repo's master branch, like so:

pip install git+https://github.com/python-amazon-mws/python-amazon-mws.git@master#egg=mws

Installing 1.0.x-dev (GitHub)

Our develop version can be installed directly from the repo using:

pip install git+https://github.com/python-amazon-mws/python-amazon-mws.git@develop#egg=mws

Note that code may be updated at any time as development continues, so please use at your own risk.

Quickstart

Export your API credentials as environment variables in your shell.

export MWS_ACCOUNT_ID=...
export MWS_ACCESS_KEY=...
export MWS_SECRET_KEY=...

Now you can experiment with the API from within an interactive Python shell e.g.

>>> import mws, os
>>> orders_api = mws.Orders(
...     access_key=os.environ['MWS_ACCESS_KEY'],
...     secret_key=os.environ['MWS_SECRET_KEY'],
...     account_id=os.environ['MWS_ACCOUNT_ID'],
...     region='UK',   # defaults to 'US'
... )
>>> service_status = orders_api.get_service_status()
>>> service_status
<mws.mws.DictWrapper object at 0x1063a2160>
>>> service_status.original
'<?xml version="1.0"?>\n<GetServiceStatusResponse xmlns="https://mws.amazonservices.com/Orders/2013-09-01">\n  <GetServiceStatusResult>\n    <Status>GREEN</Status>\n    <Timestamp>2017-06-14T16:39:12.765Z</Timestamp>\n  </GetServiceStatusResult>\n  <ResponseMetadata>\n    <RequestId>affdec68-05d2-4bc5-a8a4-bb40f307dd6b</RequestId>\n  </ResponseMetadata>\n</
GetServiceStatusResponse>\n'
>>> service_status.parsed
{'value': '\n    ', 'Status': {'value': 'GREEN'}, 'Timestamp': {'value': '2017-06-14T16:39:12.765Z'}}
>>> service_status.response
<Response [200]>

Development

To get started with development, first clone this repo, then install the package locally with extra dependencies:

# development tooling (Black, Flake8, Isort
pip install -e .[develop]
# documentation tools
pip install -e .[docs]
# both of the above
pip install -e .[develop,docs]
# or, just everything
pip install -e .[all]

Using pre-commit framework

This project uses the pre-commit framework. This framework installs a Git pre-commit hook that runs scripts as detailed in .pre-commit-config.yaml on commits in your local clone of the repo. These hooks are used to ensure code quality when contributing to the project.

The pre-commit package should already be installed along with installing development requirements (above), but is "opt-in" by design. We highly encourage using it in your local environment. To do so, install the hooks with:

pre-commit install

Pre-commit hook scripts will only run against the files that you change within a commit for speed purposes. To run the hooks against all files in the project, use:

pre-commit run --all-files

Tests

Tests are run with pytest. To run tests, simply install our dev requirements and then run:

pytest

See pytest docs for details on selecting specific tests, rather than the entire test suite, as needed.

We also perform coverage reporting using pytest-cov. You can generate a coverage report locally using:

pytest --cov=mws

You may also want to generate a local HTML report to navigate the code and see where coverage is missing:

pytest --cov=mws --cov-report html

This will create a htmlcov/ directory, and you can open htmlcov/index.html to view the report in your browser.

The test suite and coverage reporting to Codecov are run automatically in the repo on pushes and pull requests, using GitHub Actions workflows. We test on latest versions of Python 3.5+, and on latest Ubuntu, Mac, and Windows OSes.

Documentation

Docs are built using Sphinx.

To build docs locally, use make:

make html

The output HTML documentation will be in docs/build/.

To run a live reloading server serving the HTML documentation (on localhost:8000 or 127.0.0.1:8000 by default):

make livehtml

On Windows

make may not be available on Windows, but you can still build documentation with sphinx-build and sphinx-autobuild.

To build the docs locally, use sphinx-build:

sphinx-build -b html docs/source docs/build

You can also run a live-reloading server using sphinx-autobuild (on localhost:8000 or 127.0.0.1:8000 by default):

sphinx-autobuild docs/source docs/build

Contributing

Please make pull requests to develop. Code coverage isn't necessary but encouraged where possible.

Support

For support using the package, please join our Slack and post in the #help channel.

For support using MWS itself, we advise using the MWS documentation

python-amazon-mws's People

Contributors

agritheory avatar albrnick avatar bloodywing avatar bobspadger avatar chronossc avatar czpython avatar dezetage avatar elcolumbio avatar griceturrble avatar jameshiew avatar josh-dwernychuk avatar kleinernull avatar kushgoyal avatar madelyneriksen avatar masavini avatar mdaif avatar mpatek avatar natim avatar nickspring avatar null-none avatar ojii avatar oxodao avatar patgarcia avatar pre-commit-ci[bot] avatar ronbeltran avatar ryan-daly avatar samamorgan avatar sfeuerwerker avatar tgehrs avatar xmo-odoo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-amazon-mws's Issues

drop pyhon 2.7 support in 1.0 release

  • We are a small library, so we really should have a relentless focus on improving.
    I just found an example dicussion in our upstream dependency requests.
    An argument is in 18 month pyhon 2.7 is dead. Tests will start to break ...
    But it will be way sooner, since our upstream dependencies will switch earlier.

We can release a stable 0.9 which people can use, if they like to use old software in the first place.

To support python 2.7 is already taking like 1/5 additional efforts, which could be better spent.

HTTPError with certain number of items

Hello,

On several different function calls in the "InboundShipments" class (possibly present in other calls as well) I'm getting either a 502 Server Error or a 400 Client Error when trying to submit a request after there is a certain number of items, even if the number is far below the throttling limit.

For example, with the "UpdateInboundShipment" function, I have no problem submitting a request that contains something like 10-15 SKUs. However, if I try to submit a request that has more than about 30 SKUs, I consistently get one of the two above errors. According to the documentation this request can have up to 200 items so it doesn't seem to be related to throttling. Possibly something related to the URL length?

Anyone else experiencing this issue? I can divide up my SKUs into multiple calls to make it functional but I'm interested to know if this is a bug or if I'm just missing something and this is a part of the normal functionality.

Thanks for your help

Please beautify the parsed dict object :)

This mws package shall help a lot of Python programmers a lot.
So, please beautify the parsed dict object :)

  • What are so many 'value': '\n ' for?
  • 'NumberOfItemsShipped': 0, is much better than 'NumberOfItemsShipped': {'value': '0'},
  • 'CreatedBefore': {'value': '2018-05-17T07:00:00Z'} => 'CreatedBefore': '2018-05-17T07:00:00Z'

My dict lokks like:

   {'value': '\n        ',
    'LatestShipDate': {'value': '2018-05-17T06:59:59Z'},
    'OrderType': {'value': 'StandardOrder'},
    'PurchaseDate': {'value': '2018-05-16T19:46:17Z'},
    'AmazonOrderId': {'value': '113-8006225-0697855'},
    'IsReplacementOrder': {'value': 'false'},
    'LastUpdateDate': {'value': '2018-05-16T19:46:22Z'},
    'NumberOfItemsShipped': {'value': '0'},
    'ShipServiceLevel': {'value': 'SecondDay'},
    'OrderStatus': {'value': 'Pending'},
    'SalesChannel': {'value': 'Amazon.com'},
    'IsBusinessOrder': {'value': 'false'},
    'NumberOfItemsUnshipped': {'value': '1'},
    'PaymentMethodDetails': {'value': '\n          ',
     'PaymentMethodDetail': {'value': 'Standard'}},
    'IsPremiumOrder': {'value': 'false'},
    'EarliestShipDate': {'value': '2018-05-17T06:59:59Z'},
    'MarketplaceId': {'value': 'ATVPDKIKX0DER'},
    'FulfillmentChannel': {'value': 'AFN'},
    'PaymentMethod': {'value': 'Other'},
    'IsPrime': {'value': 'false'},
    'ShipmentServiceLevelCategory': {'value': 'SecondDay'},
    'SellerOrderId': {'value': '113-8006225-0697855'}}]},
 'CreatedBefore': {'value': '2018-05-17T07:00:00Z'},

Missing required parameter SellerId.

I'm listing categories of the product using ASIN

products_api = mws.Products(
        access_key=settings.MWS_CLIENT_KEY,
        secret_key=settings.MWS_CLIENT_SECRET,
        account_id=settings.MWS_SELLER_ID,
        region='US'
    )

    products = products_api.get_product_categories_for_asin(
        marketplaceid=settings.MWS_MARKETPLACE_ID,
        asin=asin,
    )

    print(products)

But this is giving error

mws.mws.MWSError: <?xml version="1.0"?>
<ErrorResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
  <Error>
    <Type>Sender</Type>
    <Code>InvalidParameterValue</Code>
    <Message>Missing required parameter SellerId.</Message>
  </Error>
  <RequestID>ebc6f742-43b5-4f98-b681-974599284db7</RequestID>
</ErrorResponse>

I tried same credentials with https://mws.amazonservices.com/scratchpad/index.html

and it's working fine.

Getting started

Can anyone share some sample code that works? The docs don't really help with getting started & I would like to give this a go. :)

I would be happy to submit a PR to update the docs once I get things working.

Wrong content length maybe amazon error

It was working fine 2 days back . Now Error is popping up everytime .
Here is my complete error traceback : It even has the reportid , get the report and please check whats the problem .


report ID :  11319737708017711
Exception : Wrong Contentlength, maybe amazon error...
  File "<ipython-input-3-e36bd121ae40>", line 167, in _get_report_from_reporttype_
    resp = self.reportsapi.get_report(report_id=reportid)
  File "C:\Users\Natesh\Desktop\amazon-mws\src\mws\mws.py", line 420, in get_report
    return self.make_request(data)
  File "C:\Users\Natesh\Desktop\amazon-mws\src\mws\mws.py", line 254, in make_request
    parsed_response = DataWrapper(data, response.headers)
  File "C:\Users\Natesh\Desktop\amazon-mws\src\mws\mws.py", line 126, in __init__
    raise MWSError("Wrong Contentlength, maybe amazon error...")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~\Desktop\amazon-mws\src\mws\mws.py in make_request(self, extra_data, method, **kwargs)
    247                 try:
--> 248                     parsed_response = DictWrapper(data, rootkey)
    249                 except TypeError:  # raised when using Python 3 and trying to remove_namespace()

~\Desktop\amazon-mws\src\mws\mws.py in __init__(self, xml, rootkey)
    105         self._rootkey = rootkey
--> 106         self._mydict = utils.XML2Dict().fromstring(remove_namespace(xml))
    107         self._response_dict = self._mydict.get(list(self._mydict.keys())[0], self._mydict)

~\Desktop\amazon-mws\src\mws\mws.py in remove_namespace(xml)
     97     regex = re.compile(' xmlns(:ns2)?="[^"]+"|(ns2:)|(xml:)')
---> 98     return regex.sub('', xml)
     99 

TypeError: cannot use a string pattern on a bytes-like object

During handling of the above exception, another exception occurred:

ParseError                                Traceback (most recent call last)
~\Desktop\amazon-mws\src\mws\mws.py in make_request(self, extra_data, method, **kwargs)
    250                     # When we got CSV as result, we will got error on this
--> 251                     parsed_response = DictWrapper(response.text, rootkey)
    252 

~\Desktop\amazon-mws\src\mws\mws.py in __init__(self, xml, rootkey)
    105         self._rootkey = rootkey
--> 106         self._mydict = utils.XML2Dict().fromstring(remove_namespace(xml))
    107         self._response_dict = self._mydict.get(list(self._mydict.keys())[0], self._mydict)

~\Desktop\amazon-mws\src\mws\utils.py in fromstring(self, str_)
    105         """
--> 106         text = ET.fromstring(str_)
    107         root_tag, root_tree = self._namespace_split(text.tag, self._parse_node(text))

c:\program files\python35\lib\xml\etree\ElementTree.py in XML(text, parser)
   1333     parser.feed(text)
-> 1334     return parser.close()
   1335 

ParseError: no element found: line 1929, column 37

During handling of the above exception, another exception occurred:

MWSError                                  Traceback (most recent call last)
<ipython-input-3-e36bd121ae40> in _get_report_from_reporttype_(self, reporttype, olderdate, laterdate)
    166 
--> 167             resp = self.reportsapi.get_report(report_id=reportid)
    168             report = None ;

~\Desktop\amazon-mws\src\mws\mws.py in get_report(self, report_id)
    419         data = dict(Action='GetReport', ReportId=report_id)
--> 420         return self.make_request(data)
    421 

~\Desktop\amazon-mws\src\mws\mws.py in make_request(self, extra_data, method, **kwargs)
    253             except XMLError:
--> 254                 parsed_response = DataWrapper(data, response.headers)
    255 

~\Desktop\amazon-mws\src\mws\mws.py in __init__(self, data, header)
    125             if header['content-md5'].encode() != hash_:
--> 126                 raise MWSError("Wrong Contentlength, maybe amazon error...")
    127 

MWSError: Wrong Contentlength, maybe amazon error...

During handling of the above exception, another exception occurred:

KeyError                                  Traceback (most recent call last)
<ipython-input-33-5b2d9a183fb9> in <module>()
----> 1 orders = obj._get_report_from_reporttype_('_GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_' , olderdate=datetime.datetime.now()-datetime.timedelta(days = 2) , laterdate=datetime.datetime.now())

<ipython-input-3-e36bd121ae40> in _get_report_from_reporttype_(self, reporttype, olderdate, laterdate)
    182             log.error('Exception : {}'.format(E)) ;
    183 
--> 184             print(resp.original)
    185 

~\Desktop\amazon-mws\src\mws\utils.py in __getattr__(self, item)
     33 
     34     def __getattr__(self, item):
---> 35         node = self.__getitem__(item)
     36 
     37         if isinstance(node, dict) and 'value' in node and len(node) == 1:

KeyError: 'original'

Is Amazon the seller

I found that I can detect the sales channel (FBM or FBA) in get_lowest_offer_listings_for_asin.

Does anyone know where I can find if Amazon is the seller?

Getting NewConnectionError

I have deployed my project on pythonanywhere . I am now using the pull request from "https://github.com/innotrade24/python-amazon-mws1" and when I run it on local machine it works .

The old version I was using (master branch version) was working fine in pythonanywhere. Once I used the library from pull request i am getting this below error .

How do I fix this ?

here is the full traceback :

They have mentioned in this site : http://help.pythonanywhere.com/pages/403ForbiddenError/ , that it needs to use a proxy for that to work but requests module automatically handles that. But in this case I am still getting the error . Please help :/

File "/home/daedalcrafters/daedal-crafters/OrderManagement/amazon_mws/interface.py", line 113, in _get_report_from_reporttype_                                                                                 
   report_request_resp = self.reportsapi.request_report(marketplace_ids=['A21TJRUUN4KGV'] , start_date= olderdate.isoformat() , end_date = laterdate.isoformat() , report_type= reporttype).parsed              
 File "/home/daedalcrafters/daedal-crafters/OrderManagement/amazon_mws/mws/apis/reports.py", line 43, in request_report                                                                                         
   return self.make_request(data)                                                                                                                                                                               
 File "/home/daedalcrafters/daedal-crafters/OrderManagement/amazon_mws/mws/mws.py", line 326, in make_request                                                                                                   
   'body', ''), headers=headers, proxies=proxies)                                                                                                                                                               
 File "/home/daedalcrafters/.virtualenvs/myenv/lib/python3.6/site-packages/requests/api.py", line 58, in request                                                                                                
   return session.request(method=method, url=url, **kwargs)                                                                                                                                                     
 File "/home/daedalcrafters/.virtualenvs/myenv/lib/python3.6/site-packages/requests/sessions.py", line 508, in request                                                                                          
   resp = self.send(prep, **send_kwargs)                                                                                                                                                                        
 File "/home/daedalcrafters/.virtualenvs/myenv/lib/python3.6/site-packages/requests/sessions.py", line 618, in send                                                                                             
   r = adapter.send(request, **kwargs)                                                                                                                                                                          
 File "/home/daedalcrafters/.virtualenvs/myenv/lib/python3.6/site-packages/requests/adapters.py", line 508, in send                                                                                             
   raise ConnectionError(e, request=request)                                                                                                                                                                    
Exception : HTTPSConnectionPool(host='mws.amazonservices.in', port=443): Max retries exceeded with url: /?AWSAccessKeyId=key&Action=RequestReport&EndDate=2018-06-30T06%3A50%3A54.982501&MWSAuthToken=mytoken&MarketplaceIdList.Id.1=A21TJRUUN4KGV&Merchant=A35G3R8LMVKV8X&ReportType=_GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_&SignatureMethod=HmacSHA256&SignatureVersion=2&StartDate=2018-05-31T06%3A50%3A54.982501&Timestamp=2018-06-30T06%3A50%3A55&Version=2009-01-01&Signature=TfTZhEGjqUD7TFF1gC02PMUo0GISNJ8pie5YUnoEAvU%3D (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f1e56950860>: Failed to establish a new connection: [Errno 111] Connection refused',))                                                                                            
^CTraceback (most recent call last):                                                                                                                                                                             
 File "/home/daedalcrafters/.virtualenvs/myenv/lib/python3.6/site-packages/urllib3/connection.py", line 141, in _new_conn                                                                                       
   (self.host, self.port), self.timeout, **extra_kw)                                                                                                                                                            
 File "/home/daedalcrafters/.virtualenvs/myenv/lib/python3.6/site-packages/urllib3/util/connection.py", line 83, in create_connection                                                                           
   raise err                                                                                                                                                                                                    
 File "/home/daedalcrafters/.virtualenvs/myenv/lib/python3.6/site-packages/urllib3/util/connection.py", line 73, in create_connection                                                                           
   sock.connect(sa)                                                                                                                                                                                             
ConnectionRefusedError: [Errno 111] Connection refused

Inventory

How would one request a full inventory report or list? There's support to use for specific skus but suppose I wanted to just know the entire inventory and dump it in a text file.

Question/Problem with certain characters

First, thanks for the work and updates to the original.

I just updated from python 2.7 to 3.6 and am (not surprisingly) running into some string errors. When executing get_matching_product_for_id, we have a number of products that should return accented characters such as: 'Publisher': {'value': 'Bärenreiter'}; however we are currently getting 'Publisher': {'value': 'Bärenreiter'}.

From the interpreter, I see the following:

  • response.parsed returns 'Publisher': {'value': 'Bärenreiter'}
  • response.original returns <ns2:Publisher>Bärenreiter</ns2:Publisher>
  • response.response.text returns <ns2:Publisher>Bärenreiter</ns2:Publisher>
  • response.response.content returns <ns2:Publisher>B\xc3\xa4renreiter</ns2:Publisher> (now we're getting somewhere!)
  • response.response.content.decode('utf-8') returns <ns2:Publisher>Bärenreiter</ns2:Publisher>

It looks like requests is interpreting the encoding incorrectly which is validated by seeing that response.response.encoding is set to 'ISO-8859-1'.

I'm pretty naive when it comes to encodings, so this may be a problem with my setup. However, since Amazon states that this XML will always be UTF-8, would it makes sense to do data = response.content.decode('utf-8') in L209 of mws.py?

Deal with Amazon's throttling

Currently its very easy to hit Amazon's api limits.

Is it worth:

a) Writing a helper system to deal with this in MWS
b) Using something existing outside of MWS (Like Tenacity)
c) Integrating Tenacity into the project as a dependancy

?

Request signature too far in the past

\n\n \n Sender\n RequestExpired\n Request signature is too far in the past and has expired. Timestamp date: 2018-09-23T10:04:57Z\n \n cc980489-5f56-4f50-ab65-ca7027d52c75\n

Some times, the above error message shows up . Any ideas why this error message occurs and how to best resolve this ?

Accessing dict information

For asin:
B071Z8LD77

I am getting data with this:
top_category = products_api.get_product_categories_for_asin(marketplaceid=marketplace_usa, asin=self.asin).parsed

{'Self': {'Parent': {'Parent': {'Parent': {'Parent': {'Parent': {'ProductCategoryId': {'value': '16310101'}, 'ProductCategoryName': {'value': 'Grocery & Gourmet Food'}}, 'ProductCategoryId': {'value': '16310211'}, 'ProductCategoryName': {'value': 'Categories'}}, 'ProductCategoryId': {'value': '16310231'}, 'ProductCategoryName': {'value': 'Beverages'}}, 'ProductCategoryId': {'value': '16521305011'}, 'ProductCategoryName': {'value': 'Coffee, Tea & Cocoa'}}, 'ProductCategoryId': {'value': '16318031'}, 'ProductCategoryName': {'value': 'Coffee'}}, 'ProductCategoryId': {'value': '14978414011'}, 'ProductCategoryName': {'value': 'Single-Serve Capsules & Pods'}}}

My question is how can I get the top-level category from this? I know I can use:
top_category.Self.Parent.Parent.Parent.Parent.Parent.ProductCategoryName but the next asin may not have this many nested levels of 'parent'.

Any ideas?

TypeError: quote_from_bytes() expected bytes

This error occurs everytime when it uses make_request method .

Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)]

~\Desktop\amazon-mws\src\mws\utils.py in _wrapped_func(self, *args, **kwargs)
    248                 # Token captured: run the "next" action.
    249                 return self.action_by_next_token(action_name, next_token)
--> 250             return request_func(self, *args, **kwargs)
    251         return _wrapped_func
    252     return _decorator

~\Desktop\amazon-mws\src\mws\mws.py in list_inventory_supply(self, skus, datetime_, response_group, next_token)
   1280                     )
   1281         data.update(utils.enumerate_param('SellerSkus.member.', skus))
-> 1282         return self.make_request(data, "POST")
   1283 
   1284     def list_inventory_supply_by_next_token(self, token):

~\Desktop\amazon-mws\src\mws\mws.py in make_request(self, extra_data, method, **kwargs)
    218         params = self.get_params()
    219         params.update(extra_data)
--> 220         request_description = calc_request_description(params)
    221         signature = self.calc_signature(method, request_description)
    222         url = "{domain}{uri}?{description}&Signature={signature}".format(

~\Desktop\amazon-mws\src\mws\mws.py in calc_request_description(params)
     78     request_description = ''
     79     for key in sorted(params):
---> 80         encoded_value = quote(params[key], safe='-_.~')
     81         request_description += '&{}={}'.format(key, encoded_value)
     82     return request_description[1:]  # don't include leading ampersand

c:\program files\python35\lib\urllib\parse.py in quote(string, safe, encoding, errors)
    710         if errors is not None:
    711             raise TypeError("quote() doesn't support 'errors' for bytes")
--> 712     return quote_from_bytes(string, safe)
    713 
    714 def quote_plus(string, safe='', encoding=None, errors=None):

c:\program files\python35\lib\urllib\parse.py in quote_from_bytes(bs, safe)
    735     """
    736     if not isinstance(bs, (bytes, bytearray)):
--> 737         raise TypeError("quote_from_bytes() expected bytes")
    738     if not bs:
    739         return ''

TypeError: quote_from_bytes() expected bytes

Increase test coverage for requests by checking input params

Given the nature of the package, it is not currently possible to test all the different request methods through automation, since testing responses requires valid Amazon Seller credentials to make a connection. Even if we were able to use Seller credentials to perform an automated test, there is no (last I heard) testing environment on the MWS side, so any request made has potential to wreak havoc in that Seller's production environment.

Rather than try to check MWS's response, we can make testing simpler by stopping short of actually sending a request. All that is really needed is to get either the parameter dict or the request string that a given request method constructs, testing that against pre-set data.


I am thinking the best option is to have an attribute on the base MWS class, something like debug_params, as a boolean. When testing, we just switch it to True, then make_request would be set to return the full param set instead of sending a request. Our test cases for these requests then need to initialize the APIs and switch on this "debug mode" in order to proceed.

This does mean that some code would not be covered, specifically the latter half of make_request that builds a DictWrapper or DataWrapper from the response. We can find some ways to cover that separately later, though, since right now I think covering the request methods is more important.

response.parsed is None when querying Reports API

The response.original and response.response.text both return the correct response but the response.parsed returns None .

When I manually converted using mws.utils.XML2Dict().fromstring( reponse.oriiginal) i got the parsed result.

I had used the Reports API with Report Type as : _GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_

Naming convention

How do you want to access the response?

First of all good news the code gets a lot easier. You could see a lot of places where it wasn't understood correctly.
For example the parsed method is doing nothing for reports, it's just passing on a string, or bytes. From now on only a better encoded string.

A. For the request.response object resolve duplicates choose one of:

  1. self.original
  2. self.response

B. Default:

  1. use self.parsed no matter what, aka """Recieve a nice formatted response, this can be your default."""
  2. dependent on text and xml. Since text we dont parse we just access it with request.original.text

C. For XML Data we provide more options:

  1. a python dictionary, we can name it pydict , should it also get a parsed method?

additional:
headers object

Proxy not getting set in the make_request method .

I have instantiated the Orders class like this with a proxy of "proxy.server:3128" .
mws.Orders(access_key=ACCESS_KEY , secret_key=SECRET_KEY , auth_token= AUTH_TOKEN , account_id = 'A35G3R8LMVKV8X' , region='IN' , proxy="proxy.server:3128")

When I added a print("proxies = " , proxies) in the make_request method , it prints : proxies = {'http': None, 'https': None}

This is a small snippet from the make_request method in which I am printing the proxies.


 try:
            # The parameters are included in the url string.
            print("proxies = " , proxies ) ; 
            response = requests.request(method, url, data=kwargs.get(
                'body', ''), headers=headers, proxies=proxies)
            response.raise_for_status()

            if 'content-md5' in response.headers:
                validate_hash(response)
            parsed_response = DataWrapper(response, rootkey)

Timestamp error (timestamp must follow ISO8601) while querying the reports API

While querying the reports API:

r = reports_api.get_report_list(types="xxx",fromdate='01-09-2018', todate='05-09-2018')

the following error is received:

python3.6/site-packages/mws/mws.py", line 261, in make_request
    raise error
mws.mws.MWSError: <?xml version="1.0"?>
<ErrorResponse xmlns="http://mws.amazonaws.com/doc/2009-01-01/">
  <Error>
    <Type>Sender</Type>
    <Code>MalformedInput</Code>
    <Message>timestamp must follow ISO8601</Message>
  </Error>

Is anyone else facing the same issue?

Feeds API getting data

I've been trying to get the data out of the get_feed_submission list here:
feedlist = feeds_api.get_feed_submission_list
for which there is the normal object response at some address...
<bound method Feeds.get_feed_submission_list of <mws.mws.Feeds object at 0x11a586080>>

However whenever I try to get the data using the usual methods I can't seem to get them to work.
something = feedlist.response
AttributeError: 'function' object has no attribute 'response'
something1 = feedlist.original
AttributeError: 'function' object has no attribute 'original'
somehting2 = feedlist.parsed
AttributeError: 'function' object has no attribute 'parsed'

so I was wondering how to get the data from this feeds object

character encoding

I have a character encoding issue with orders.parsed from the orders_api.

print(orders.parsed['Orders']['Order']) shows:
CIUDAD DE MÃ\x89XICO
which should be:
CIUDAD DE MÉXICO

I'm using Python 3.6.5 on MacOS Mojave

next token decorator

I really like that we use the decorator.
Why do we need the additional abstraction level around the NEXT_TOKEN_OPERATIONS constant?

If something like this is a lot better, i can make a pull request.

def next_token_action(action_name):
            next_token = kwargs.pop('next_token', None) 
            if next_token is not None: 
                # Token captured: run the "next" action. 
                #removed: return self.action_by_next_token(action_name, next_token) 
                action =action_name + 'ByNextToken'  # new
                data = {'Action': action, 'NextToken': next_token}   # new
                return self.make_request(data, method="POST")   # new
            return request_func(self, *args, **kwargs) 
        return _wrapped_func 
    return _decorator

I would remove everything in mws.Mws and the NEXT_TOKEN_OPERATIONS constant.

@next_token_action('ListOrderItems')
and delete the other 3 places where we defined 'ListOrderItems'. That's not changing too much.

Feature request: Always return list of items

for example, when using the Orders.list_order_items method, it is always necessary to do

isinstance(order_items.parsed.OrderItems.OrderItem, list)

This is repetition on a grand scale, so could possibly do we fixing in the module.

It may not be sensible to make this happen for ALL parts of the module as it could cause problems. Possibly just in select 'pinch points'

NextToken corrupted

Hi,

First, thanks a lot for your work! It made it really easy to communicate with MWS.

I'm trying to retrieve all orders since a long time ago, and I have to go through a lot of pages, using "orders_api.list_order_items_by_next_token()"

My issue is that MWS is returning an error :

MWSError: <?xml version="1.0"?> <ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2013-09-01"> <Error> <Type>Sender</Type> <Code>NextTokenCorrupted</Code> <Message>We could not decode your NextToken.</Message> </Error> <RequestId>66a476d9-5e39-4749-9d24-0f0eb144c2de</RequestId> </ErrorResponse>

My Token : '94HPGhjwKyV/YYuZQbKv1QafEPREmauvizt1MIhPYZZbsgeHy/DuWGI4ng+mAxhBnCRKY29ynn3NeGyEmOrLe7q8xqAchQNKtU38YwqRuVIwqcbUqh/LhCJ0wMvlylZkE3RvwDUQBA2PLkbo+RzWuc0I2oB+AODGnOuH9R+FS+UrZQy/V771Wx35jNz11rwFrh4UqkkfQWA2QiSqpH/3gzvpWxLDu6V0kSSzHy0mGpCfpVJGS+vu5pFHMXy6XL5l/6rjAfCll94wI2FDUn7uCTzBkCWg0Z/wsJdJobvDtjaUELdOx1y44x2EM4mxRhI1BfS02qhrrgmld87/uwC4WaomF+AypslNStz4vwzMbNU93cf9JM/dXCDd8WY6S5qIC7lkadWl+YjiGdvkjrjldO07RNBq9UDfR2MsVNGnbkXLc/qP8a7QJ8Een7QBpmb/G8zE6YuflsyoTzmSGfWp2PyAULdxUEMyTzGCBmL1RoSabG1W2DI/elTKWZCcypVTY6OSkm5sDP9ZJvmuQ0mk4Epd8Re7bpJfPMG4jNqghnlDZBmR6xJsEr5KRLN5wRPF1YGxuBKk5+eybflF5uWu/iHPH7EsHndai5Q+A8Zi3sU='

What could be the issue? Any tips on how to fix this ?

Need a "clean" method for parameter validation

While writing some request method tests recently, I came across some mild confusion, conceptually speaking.

We perform a parameter validation for datetimes within the make_request method, here:

for key, value in extra_data.items():
if isinstance(value, (datetime.datetime, datetime.date)):
extra_data[key] = value.isoformat()

Aside from this, params are not validated much further. The next time they are touched in a similar fashion is inside calc_request_description:

for key, val in params.items():
encoded_val = quote(str(val), safe='-_.~')
description_items.append('{}={}'.format(key, encoded_val))
return '&'.join(sorted(description_items))

Here, the parameter value passes through str and urllib.parse.quote (on Python 2, urllib.quote). That str conversion is necessary to prevent errors when passing the value through quote, which is fine.


Problem: These two spots represent two different points of input validation that only A) convert datetime objects to strings in ISO-8601 format, and B) convert any other value to str (while not catching any exceptions that could be raised by str). While it isn't breaking much, it limits options for further validation, as well as adding some confusion as to whether and/or when any validation is being performed.


Solution: Would like to write a "clean" method that all parameters pass through, taking the "raw" parameters as input and returning a "cleaned" version of the params dict. Downstream code should be able to rely on every value of the parameter dict being a string or a useful exception being raised if a parameter value cannot be converted.

The "clean" method should be called inside the make_request method, in about the same spot as the current datetime validation code (the call to the "clean" method should replace that validation, in fact).


At time of writing, I'm busy with test methods, day job, and home stuff. If anyone else wants to pick this off, feel free to do so.

Incorporate methods from `python-amazon-mws-tools`?

Came across this recently: python-amazon-mws-tools.

The tools are meant as a companion for python-amazon-mws (as forked from the upstream by czpython), adding wrappers to process incoming data into more meaningful Python objects.

I haven't dug into it much, but it might be a good jumping-off point to adding some more intelligent behavior into the base project.

Request for new maintainer

Unfortunately I cannot maintain this package any longer. There are some great PRs and I don't have the focus now to properly integrate them, but it would be a shame to let them sit still. If you think you'd be up for maintaining the package and have some experience with python-amazon-mws I can move this Github repo over to an organization and also transfer over the pip package.

Reports - max_count

Hello,
I have (had) an issue with Reports.get_report_list()

If I call get_report_list(max_count=100), I run into the error

File "/home/amzteu/app/bin/mws.py", line 85, in calc_request_description
encoded_value = quote(params[key], safe='-_.~')
File "/usr/lib64/python2.7/urllib.py", line 1280, in quote
if not s.rstrip(safe):
AttributeError: 'int' object has no attribute 'rstrip'

After some debug, this can be easily fixed by calling
get_report_list(max_count='100')
Basically passing a text instead of an integer (line 438, param max_count)

In my opinion max_count makes more sense as a number, so it would be better to edit line 444 into MaxCount=str(max_count))

Thanks,
Alberto

Add marketplace ID enums

At the moment they appear in the comments, but it would be useful if they were exposed as enums

Getting syntax error when using mws.utils.XML2Dict().fromstring

Getting syntax error when I manually call the mws.utils function (Since i got response.parsed as None)

Traceback (most recent call last):

  File "<ipython-input-126-6b6416847cb5>", line 64, in get_all_orders
    parsedstring = (mws.utils.XML2Dict().fromstring(resp.response.text))

  File "/home/natesh/Desktop/AMAZON_MWS/src/mws/utils.py", line 106, in fromstring
    text = ET.fromstring(str_)

  File "/usr/lib/python3.6/xml/etree/ElementTree.py", line 1314, in XML
    parser.feed(text)

  File "<string>", line unknown
ParseError: syntax error: line 1, column 0

The syntax error happens because of this kind of non xml response in response.origianl =
b'Date range exceeded. Report can be requested only upto 30 days\r\n'

enable deepcopy for DictWrapper

i run into this because i want to dump the response object into a yaml file.

products_api = mws.Products()
products = products_api.get_x()
mydict = vars(products)  # same as products.__dict__
type(mydict['_response_dict'])

this returns
luigipipe.mws.mws.utils.ObjectDict

i think it should return: dict

A very simple approach for problems of that kind i found here.

If you think that is a good idea i can try to understand and fix this.

Develop Branch: get_competitive_pricing_for_sku

Using the following:

sku_list:

['arttpatch', 'dun474p20', 'epippegenplawch1', 'fatnumacompact2', 'fen0113010705', 'fen0144603502', 'fen0144603506', 'fen0144703580', 'fen0146102502', 'fen0197002706', 'gen8330apm', 'gro5ar4', 'hosbnc58110', 'hosbnc58115', 'hoswti172', 'ibaaf75gbkf', 'ibarg370ahmzbmt', 'levmpd2036', 'lin30435', 'lin30437']

Requesting competitive pricing for this list of items works on the current mws master branch, but fails with the new develop.

Outputting the following error

<?xml version="1.0"?>
<ErrorResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
  <Error>
    <Type>Sender</Type>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message>
  </Error>
  <RequestID>b5c4fb44-54be-41b3-85a0-58d321758f70</RequestID>
</ErrorResponse>
<?xml version="1.0"?>
<ErrorResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
  <Error>
    <Type>Sender</Type>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message>
  </Error>
  <RequestID>b5c4fb44-54be-41b3-85a0-58d321758f70</RequestID>
</ErrorResponse><?xml version="1.0"?>
<ErrorResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
  <Error>
    <Type>Sender</Type>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message>
  </Error>
  <RequestID>b5c4fb44-54be-41b3-85a0-58d321758f70</RequestID>
</ErrorResponse>

I believe this is to do with the description being calculated differently on this branch and will investigate.

Failed:

AWSAccessKeyId=[REDACTED]&Action=GetCompetitivePricingForSKU&MarketplaceId=A1F83G8C2ARO7P&SellerId=[REDACTED]&SellerSKUList.SellerSKU.10=fen0197002706&SellerSKUList.SellerSKU.11=gen8330apm&SellerSKUList.SellerSKU.12=gro5ar4&SellerSKUList.SellerSKU.13=hosbnc58110&SellerSKUList.SellerSKU.14=hosbnc58115&SellerSKUList.SellerSKU.15=hoswti172&SellerSKUList.SellerSKU.16=ibaaf75gbkf&SellerSKUList.SellerSKU.17=ibarg370ahmzbmt&SellerSKUList.SellerSKU.18=levmpd2036&SellerSKUList.SellerSKU.19=lin30435&SellerSKUList.SellerSKU.1=arttpatch&SellerSKUList.SellerSKU.20=lin30437&SellerSKUList.SellerSKU.2=dun474p20&SellerSKUList.SellerSKU.3=epippegenplawch1&SellerSKUList.SellerSKU.4=fatnumacompact2&SellerSKUList.SellerSKU.5=fen0113010705&SellerSKUList.SellerSKU.6=fen0144603502&SellerSKUList.SellerSKU.7=fen0144603506&SellerSKUList.SellerSKU.8=fen0144703580&SellerSKUList.SellerSKU.9=fen0146102502&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2018-03-20T12%3A34%3A24&Version=2011-10-01

Works:

AWSAccessKeyId=[REDACTED]&Action=GetCompetitivePricingForSKU&MarketplaceId=A1F83G8C2ARO7P&SellerId=[REDACTED]&SellerSKUList.SellerSKU.1=arttpatch&SellerSKUList.SellerSKU.10=fen0197002706&SellerSKUList.SellerSKU.11=gen8330apm&SellerSKUList.SellerSKU.12=gro5ar4&SellerSKUList.SellerSKU.13=hosbnc58110&SellerSKUList.SellerSKU.14=hosbnc58115&SellerSKUList.SellerSKU.15=hoswti172&SellerSKUList.SellerSKU.16=ibaaf75gbkf&SellerSKUList.SellerSKU.17=ibarg370ahmzbmt&SellerSKUList.SellerSKU.18=levmpd2036&SellerSKUList.SellerSKU.19=lin30435&SellerSKUList.SellerSKU.2=dun474p20&SellerSKUList.SellerSKU.20=lin30437&SellerSKUList.SellerSKU.3=epippegenplawch1&SellerSKUList.SellerSKU.4=fatnumacompact2&SellerSKUList.SellerSKU.5=fen0113010705&SellerSKUList.SellerSKU.6=fen0144603502&SellerSKUList.SellerSKU.7=fen0144603506&SellerSKUList.SellerSKU.8=fen0144703580&SellerSKUList.SellerSKU.9=fen0146102502&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2018-03-20T12%3A41%3A27Z&Version=2011-10-01

Remove `__all__` from mws.py

The upstream didn't have an __all__, it was a bad idea of me to add this in. I thought it made things cleaner but actually some applications might import things like MWS which is not listed in __all__. I actually have an application I developed some years back which does this.

General Announcements [2019-03-26: getting back in the swing of things]

For lack of a solid option at the moment and a lack of desire to set up a proper blog right now, I am using this issue as an announcement. So: hi, folks. 😃

Updates

2018-06-01

We've had some progress lately, mainly thanks to contributors donating their time. Thank you to those who have added content recently to improve the project. :) (full comment)

2018-05-08

Quick update: we have detached python-amazon-mws from the original upstream repo, so this is now a "normal" repository. (full comment)

2018-03-10

Update to an update: I've merged feature-request-testing branch to develop. This provides a framework for request method automated testing throughout the project, with some example tests provided for the Inventory API. (full comment)


Original post from 2018-03-10 follows

All current PRs have been merged and accepted into the develop branch, bringing that branch up-to-date with the current set of changes. Now's a good time for a change I've been working on, separating the mws module into component modules.

API modules

Each MWS API will be covered by the same class of the same name as before. Now, however, code will be moved into the apis sub-directory. Each API lives within its own module, which allows for easier editing in future as we don't need to sift through the monolithic mws module to make those changes.

As much as possible, I've tried to ensure that the changes remain backwards-compatible:

  • You should still be able to access API classes using the style from mws import ApiClass.
  • breaking change: if your code relied on an import such as from mws.mws import ApiClass, this will no longer work. You must edit downstream code to match from mws import ApiClass
  • Alternatively, from mws.apis import ApiClass will work just the same, though this not necessary.
    • You could get even more specific, if you like: from mws.apis.inventory import Inventory. This is almost positively not necessary for accessing the API class.

New space for API-specific code

Because APIs are now separated into component modules, there is now ample space for additional data, constants, and functions specific to that API. For example, we may expand on sections such as the Reports API to include constants for each ReportType enumeration, which can aid both internal code (adding checks for the enumeration used) and downstream development (providing easy access to the enumeration types, relieving some of the pressure on end users to dive into Amazon MWS documentation every time they want to make a change).

An example of this will be present in the InboundShipments API, with the use of the separate parse_item_args method (previously a method of the InboundShipments class).

Decorators

With the introduction of the InboundShipments API, we provided a decorator for next_token_action, allowing users to call the same request method with a next_token kwarg to automatically call that method's ByNextToken action. This decorator was previously housed in the utils module.

With this update, I've moved it into its own decorators module, which can be home to other useful decorators in future, if necessary.

Roadmap

As mentioned, this change is being merged into the develop branch today. I would have waited until after a 0.9 release first, but I felt it best to push it earlier so that others can play around with it as we continue to move forward in fixing up the project. Further, since there are some (albeit minor) breaking changes with this merge, a new minor release just won't cut it.

Therefore, the next release will be 1.0. I'm looking to bolster the functionality of the project so that it can cover a majority of use-cases and function as the de facto version of python-amazon-mws in the wild. The "roadmap" project will be updated later today to reflect this.

On that last note ("being the de facto version of python-amazon-mws"): once we move to a 1.0 release, I will be requesting that this project be separated from its upstream (by czpython). That will provide us with a bit more control over the project and some additional tools (searching this repo is not currently possible, because it is still technically a fork).

Q&A

Feel free to post questions here regarding these changes, future plans, and so on. Thank you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.