Json dumping a dict throws TypeError: keys must be a string

Deadly 提交于 2019-11-28 08:25:15
bigblind

You could try to clean it up like this:

for key in mydict.keys():
  if type(key) is not str:
    try:
      mydict[str(key)] = mydict[key]
    except:
      try:
        mydict[repr(key)] = mydict[key]
      except:
        pass
    del mydict[key]

This will try to convert any key that is not a string into a string. Any key that could not be converted into a string or represented as a string will be deleted.

Modifying the accepted answer above, I wrote a function to handle dictionaries of arbitrary depth:

def stringify_keys(d):
    """Convert a dict's keys to strings if they are not."""
    for key in d.keys():

        # check inner dict
        if isinstance(d[key], dict):
            value = stringify_keys(d[key])
        else:
            value = d[key]

        # convert nonstring to string if needed
        if not isinstance(key, str):
            try:
                d[str(key)] = value
            except Exception:
                try:
                    d[repr(key)] = value
                except Exception:
                    raise

            # delete old key
            del d[key]
    return d

Nolan conaway's answer gives this result for example

{"b'opening_hours'": {"b'1_from_hour'": 720, "b'1_to_hour'": 1440, "b'1_break_from_hour'": 1440, "b'1_break_to_hour'": 1440, "b'2_from_hour'": 720, "b'2_to_hour'": 1440, "b'2_break_from_hour'": 1440, "b'2_break_to_hour'": 1440, "b'3_from_hour'": 720, "b'3_to_hour'": 1440, "b'3_break_from_hour'": 1440, "b'3_break_to_hour'": 1440, "b'4_from_hour'": 720, "b'4_to_hour'": 1440, "b'4_break_from_hour'": 1440, "b'4_break_to_hour'": 1440, "b'5_from_hour'": 720, "b'5_to_hour'": 1440, "b'5_break_from_hour'": 1440, "b'5_break_to_hour'": 1440, "b'6_from_hour'": 720, "b'6_to_hour'": 1440, "b'6_break_from_hour'": 1440, "b'6_break_to_hour'": 1440, "b'7_from_hour'": 720, "b'7_to_hour'": 1440, "b'7_break_from_hour'": 1440, "b'7_break_to_hour'": 1440}}

while this amended version

import time import re import json from phpserialize import *

class Helpers:
   def stringify_keys(self,d):
    """Convert a dict's keys to strings if they are not."""
    for key in d.keys():
        # check inner dict
        if isinstance(d[key], dict):
            value = Helpers().stringify_keys(d[key])
        else:
            value = d[key]
        # convert nonstring to string if needed
        if not isinstance(key, str):
            try:
                d[key.decode("utf-8")] = value
            except Exception:
                try:
                    d[repr(key)] = value
                except Exception:
                    raise

            # delete old key
            del d[key]
    return d

will give this cleaner version..

{"opening_hours": {"1_from_hour": 720, "1_to_hour": 1440, "1_break_from_hour": 1440, "1_break_to_hour": 1440, "2_from_hour": 720, "2_to_hour": 1440, "2_break_from_hour": 1440, "2_break_to_hour": 1440, "3_from_hour": 720, "3_to_hour": 1440, "3_break_from_hour": 1440, "3_break_to_hour": 1440, "4_from_hour": 720, "4_to_hour": 1440, "4_break_from_hour": 1440, "4_break_to_hour": 1440, "5_from_hour": 720, "5_to_hour": 1440, "5_break_from_hour": 1440, "5_break_to_hour": 1440, "6_from_hour": 720, "6_to_hour": 1440, "6_break_from_hour": 1440, "6_break_to_hour": 1440, "7_from_hour": 720, "7_to_hour": 1440, "7_break_from_hour": 1440, "7_break_to_hour": 1440}}

Ideally you would want to clean your data so you comply to the data types supported by JSON.

If you simply want to suppress/ or remove these elements from the dict while serializing, you can use skipkeys argument, description can be found in json.dump section

json.dumps(obj, skipkeys=True)

This solution is much cleaner and allows the standard library handle erroneous keys for you.

WARNING: You must fully understand the implications of using such a drastic method as this will result in data loss for non-compliant data types as JSON keys.

Donnie

Maybe this will help the next guy:

strjson = json.dumps(str(dic).replace("'",'"'))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!