Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python string encoding issue

I am using the Amazon MWS API to get the sales report for my store and then save that report in a table in the database. Unfortunately I am getting an encoding error when I try to encode the information as Unicode. After looking through the report (exactly as amazon sent it) I saw this string which is the location of the buyer:

'S�o Paulo'

so I tried to encode it like so:

encodeme = 'S�o Paulo'
encodeme.encode('utf-8)

but got the following error

UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 1: ordinal not in range(128)

The whole reason why I am trying to encode it is because as soon as Django sees the character it throws a warning and cuts off the string, meaning that the location is saved as S instead of

São Paulo

Any help is appreciated.

like image 232
Paulo Avatar asked Mar 01 '26 20:03

Paulo


1 Answers

It looks like you are having some kind of encoding problem.

First, you should be very certain what encoding Amazon is using in the report body they send you. Is it UTF-8? Is it ISO 8859-1? Something else?

Unfortunately the Amazon MWS Reports API documentation, especially their API Reference, is not very forthcoming about what encoding they use. They only encoding I see them mention is UTF-8, so that should be your first guess. The GetReport API documentation (p.36-37) describes the response element Report as being type xs:string, but I don't see where they define that data type. Maybe they mean XML Schema's string datatype.

So, I suggest you save the byte sequence you are receiving as your report body from Amazon in a file, with zero transformations. Be aware that your code which calls AWS might be modifying the report body string inadvertently. Examine the non-ASCII bytes in that file with a binary editor. Is the "São" of "São" stored as S\xC3\xA3o, indicating UTF-8 encoding? Or is it stored as S\xE3o, indicating ISO 8859-1 encoding?

I'm guessing that you receive your report as a flat file. The Amazon AWS documentation says that you can request reports be delivered to you as XML. This would have the advantage of giving you a reply with an explicit encoding declaration.

Once you know the encoding of the report body, you now need to handle it properly. You imply that you are using the Django framework and Python language code to receive the report from Amazon AWS.

One thing to get very clear (as Skirmantas also explains):

  • Unicode strings hold characters. Byte strings hold bytes (octets).
  • Encoding converts a Unicode string into a byte string.
  • Decoding converts a byte string into a Unicode string.

The string you get from Amazon AWS is a byte string. You need to decode it to get a Unicode string. But your code fragment, encodeme = 'São Paulo', gives you a byte string. encodeme.encode('utf-8) performs an encode() on the byte string, which isn't what you want. (The missing closing quote on 'utf-8 doesn't help.)

Try this example code:

>>> reportbody = 'S\xc3\xa3o Paulo'   # UTF-8 encoded byte string
>>> reportbody.decode('utf-8')        # returns a Unicode string, u'...'
u'S\xe3o Paulo'

You might find some background reading helpful. I agree with Hoxieboy that you should take the time to read Python's Unicode HOWTO. Also check out the top answers to What do I need to know about Unicode?.

like image 95
Jim DeLaHunt Avatar answered Mar 04 '26 08:03

Jim DeLaHunt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!