JSON encode/decode GTK enums

痞子三分冷 提交于 2019-12-05 18:44:27

The observed behavior occurs because the value gtk.PAGE_ORIENTATION_LANDSCAPE is an instance of class 'gtk._gtk.PageOrientation' which inherits type 'gobject.GEnum' which in turn inherits type 'int'.

So your GTK-enums are ints, and the json code assumes it can handle ints and thus does not call the default method of your encoder.

Unfortunately the current json implementation isn't that helpful in encoding subclassed types like this :-/ No inheriting and overriding makes this possible (at least I cannot find any solution for this). Just too many hardcoded places where the value is checked for isinstance(value, (int, long)).

But you can of course patch the source of the json encoder to achieve your goal without having to implement the whole json functionality anew. For this copy the file encoder.py from the json library (for me this is /usr/lib/python2.7/json/encoder.py) to your working directory and patch it.

In the functions _iterencode_list() and _iterencode_dict() (they are local to function _make_iterencode()) you can find checks for being of type int or long; if so, the current implementation just calls str(value). Change that to encodeInt(value) (in three places!) and implement your own encodeInt() function in encoder.py:

def encodeInt(value):
  try:
    return value.value_name
  except:
    return str(value)

Then, in your original code, you will have to import directly that patched file:

import encoder

and you will have to make sure the C implementation isn't used anymore but instead the patched code. (You see, normally, the (faster) C implementation is used, and that Python code in which we patched something is not.) To achieve this, just add after the import:

encoder.c_make_encoder = None

Now your patched encoder can be used:

print encoder.JSONEncoder().encode({
  gtk.PAGE_ORIENTATION_PORTRAIT: [
    gtk.PAGE_ORIENTATION_LANDSCAPE
  ],
  gtk.PAGE_ORIENTATION_LANDSCAPE: gtk.PAGE_ORIENTATION_PORTRAIT })

prints:

{"GTK_PAGE_ORIENTATION_PORTRAIT": [GTK_PAGE_ORIENTATION_LANDSCAPE], "GTK_PAGE_ORIENTATION_LANDSCAPE": GTK_PAGE_ORIENTATION_PORTRAIT}

Note that Json dict keys always must be strings. That's why your values get double quotes when used as keys. But that's a fate even normal ints — when used as keys — share. They also get stringified.

You can have a look at http://pastebin.com/2HAtN9E8 to see all the sources.

I found a solution, although this may not work for gtk, it does however work for enums in general.

If you can use IntEnum instead of Enum, then you can override str in your Enum class to return a string of whatever you want, name or value most likely.

import json
from enum import IntEnum

class TrekCaptains(IntEnum):
    Kirk  = 0
    Picard = 1

    def __str__(self):
        return '{0}'.format(self.value)


s = {TrekCaptains.Kirk:'Original Series',
     TrekCaptains.Picard:'Next Generation'}
j = json.dumps(s)
print j

#result
#{"0": "Original Series", "1": "Next Generation"}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!