3

I'm building a fairly large JSON dictionary where I specify a few uuids like this:

import uuid

game['uuid'] = uuid.uuid1()

I'm getting a type error with the following traceback. I'm not sure what the issue is because we can have UUIDs within json objects

Traceback (most recent call last):
  File "/Users/claycrosby/Desktop/coding/projects/gambling/scraper/sbtesting.py", line 182, in <module>
    game_json = json.dumps(game)
  File "/opt/miniconda3/envs/ds383/lib/python3.8/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/opt/miniconda3/envs/ds383/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/opt/miniconda3/envs/ds383/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/opt/miniconda3/envs/ds383/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type UUID is not JSON serializable
[Finished in 0.5s with exit code 1]
[cmd: ['/opt/miniconda3/envs/ds383/bin/python3', '/Users/claycrosby/Desktop/coding/projects/gambling/scraper/sbtesting.py']]
[dir: /Users/claycrosby/Desktop/coding/projects/gambling/scraper]
[path: /opt/miniconda3/bin:/opt/miniconda3/condabin:/Library/Frameworks/Python.framework/Versions/3.8/bin:/Library/Frameworks/Python.framework/Versions/3.8/bin:/Users/claycrosby/Desktop/coding/programs/pbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin]
greenmeansgo
  • 441
  • 2
  • 6
  • 9

3 Answers3

5

Cast it to a string instead of using a uuid.UUID object:

game['uuid'] = str(uuid.uuid1())
That1Guy
  • 7,075
  • 4
  • 47
  • 59
5

That1Guy's answer is fine. But if you end up having to massage you data in too many places to get it to serialize, consider writing your own JSON serializer class to do it for you! For instance, here's one that turns IPV4Addresses into strings:

from json import JSONEncoder, dumps

class TMCSerializer(JSONEncoder):

    def default(self, value: Any) -> str:
        """JSON serialization conversion function."""

        # If it's an IP, which is not normally
        # serializable, convert to string.
        if isinstance(value, IPv4Address):
            return str(value)

        # Here you can have other handling for your
        # UUIDs, or datetimes, or whatever else you
        # have.

        # Otherwise, default to super
        return super(TMCSerializer, self).default(value)

Then you call it like so:

json_str = json.dumps(some_dict, cls=TMCSerializer)
Jared Smith
  • 19,721
  • 5
  • 45
  • 83
5

The uuid.UUID class itself can't be JSON serialized, but the object can be expressed in several JSON compatible formats. From help(uuid.UUID) we can see these options (though bytes would need some more work because they aren't json either).

 |      bytes       the UUID as a 16-byte string (containing the six
 |                  integer fields in big-endian byte order)
 |  
 |      bytes_le    the UUID as a 16-byte string (with time_low, time_mid,
 |                  and time_hi_version in little-endian byte order)
 |  
 |      fields      a tuple of the six integer fields of the UUID,
 |                  which are also available as six individual attributes
 |                  and two derived attributes:
 |  
 |          time_low                the first 32 bits of the UUID
 |          time_mid                the next 16 bits of the UUID
 |          time_hi_version         the next 16 bits of the UUID
 |          clock_seq_hi_variant    the next 8 bits of the UUID
 |          clock_seq_low           the next 8 bits of the UUID
 |          node                    the last 48 bits of the UUID
 |  
 |          time                    the 60-bit timestamp
 |          clock_seq               the 14-bit sequence number
 |  
 |      hex         the UUID as a 32-character hexadecimal string
 |  
 |      int         the UUID as a 128-bit integer
 |  
 |      urn         the UUID as a URN as specified in RFC 4122

If your API wants a URN for example, you'd

>>> game = {'uuid': uuid.uuid1().urn}
>>> game
{'uuid': 'urn:uuid:56fabaca-0fe6-11eb-9910-c770eddca9e7'}
>>> json.dumps(game)
'{"uuid": "urn:uuid:56fabaca-0fe6-11eb-9910-c770eddca9e7"}'
tdelaney
  • 73,364
  • 6
  • 83
  • 116