0

I have the following code, which is a function to export a transaction history from a digital currency wallet to a json file.

The problems I am facing are two:

  1. I would like to allow the json file to be written in utf-8, as the property 'label' can be utf-8 characters, and if I do not account for that, it will show up in the file as \u\u\u etc. However, no matter what combinations and orderings of encode/decode('utf-8'), I can not get the final output file to print to utf-8.

  2. I would like to order each iteration in the order I wrote them in the code. I tried OrderedDict from collection, but it did not order the items so that Date comes first, etc.

Any help with figuring out how to print this to my file using utf-8 and with the order inside each item as I wrote it.

Thank you very much.

# This line is the last line of a for loop iterating through
# the list of transactions, "for each item in list"
wallet_history.append({"Date": time_string, "TXHash": tx_hash, "Label": label, "Confirmations":
                      confirmations, "Amount": value_string, "Fee": fee_string, "Balance": balance_string})
try:
    history_str = json.dumps(
        wallet_history, ensure_ascii=False, sort_keys=False, indent=4)
except TypeError:
    QMessageBox.critical(
        None, _("Unable to create json"), _("Unable to create json"))
    jsonfile.close()
    os.remove(fileName)
    return
jsonfile.write(history_str)
user3074620
  • 3,637
  • 1
  • 14
  • 19

2 Answers2

2

You need to ensure that both json does not escape characters, and you write your json output as unicode:

import codecs
import json

with codecs.open('tmp.json', 'w', encoding='utf-8') as f:
    f.write(json.dumps({u'hello' : u'привет!'}, ensure_ascii=False) + '\n')


$ cat tmp.json
{"hello": "привет!"}

As for your second question: you can use collections.OrderedDict, but you need to be careful to pass it directly to json.dumps without changing it to simple dict. See the difference:

from collections import OrderedDict
data = OrderedDict(zip(('first', 'second', 'last'), (1, 10, 3)))
print json.dumps(dict(data)) # {"second": 10, "last": 3, "first": 1}
print json.dumps(data) # {"first": 1, "second": 10, "last": 3}
m.wasowski
  • 6,329
  • 1
  • 23
  • 30
0

To make the generated JSON encoded in UTF-8 use ensure_ascii=False:

Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
>>> import json
>>> json.dumps(u'привет!', ensure_ascii=False)
u'"\u043f\u0440\u0438\u0432\u0435\u0442!"'
>>> print json.dumps(u'привет!', ensure_ascii=False)
"привет!"
>>> with open('test', 'w') as f:
...     f.write(json.dumps(u'привет!', ensure_ascii=False))
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-6: ordinal not in range(128)
>>> with open('test', 'w') as f:
...     f.write(json.dumps(u'привет!'.encode('utf-8'), ensure_ascii=False))
... 
>>> with open('test') as f:
...     f.read()
... 
'"\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82!"'
>>> print '"\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82!"'
"привет!"
>>>

As for the second question about order. It's not possible (except writing you own serializer) or it doesn't make sense: Items in JSON object are out of order using "json.dumps"?

When you pass wallet_history to json.dumps it's already lost its order, as it contains dictionaries, which are unordered.

Community
  • 1
  • 1
warvariuc
  • 57,116
  • 41
  • 173
  • 227
  • As you can see, I do have ensure_ascii=False, and it still doesn't write in utf-8... I think maybe it's because I am storing the dumps into a string first? Is it something to do with the file.write() function?... – user3074620 Mar 29 '14 at 06:29
  • It's working here (see my update). How are you checking that it still doesn't write in utf-8? – warvariuc Mar 29 '14 at 06:32
  • I am checking by opening the file in a text editor set to utf8 encoding. Only the labels are written in /u bytes – user3074620 Mar 29 '14 at 06:48
  • How are you opening the file `jsonfile`? Why do you pass it as the second argument to `json.dumps`? – warvariuc Mar 29 '14 at 07:06
  • Also, are you sure that `label` isn't already ASCII encoded when passed to `wallet_history.append`? – warvariuc Mar 29 '14 at 07:10