Skip to main content

PyJsonFriendly

PyJsonFriend facilitates conversion of custom made classes to JSON String using json.dumps

Examples

Example 1: Failing Example

Let's say you have the following class:

class NotJsonFriendly:
    def __init__(self, field1, field2):
        self._field1 = field1
        self._field2 = field2

Now if you create an object of type NotJsonFriendly and try to make a JSON string out of it by passing it to json.dumps, you would get a TypeError:

>>> o = NotJsonFriendly(1, 2)
>>> json.dumps(o)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../lib/python3.7/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File ".../lib/python3.7/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File ".../lib/python3.7/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File ".../lib/python3.7/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type NotJsonFriendly is not JSON serializable

Example 2: Deriving from JsonFriendly

While implementing your class, you could add JsonFriendly as one of the basis. In another words, if your custom build object/class extends JsonFriendly, then you could pass your object to json.dumps. Let's say we have the following class:

from PyJsonFriendly import JsonFriendly
class DerivedJsonFriendly(JsonFriendly):
    def __init__(self, field1, field2):
        self._field1 = field1
        self._field2 = field2

    # You would need to add the following method
    def _as_json_friendly_obj(self):
        return {"field1": self._field1, "field2": self._field2}

JsonFriendly is an abstract class, which has only one abstract method called: _as_json_friendly_obj. Therefore, you wold need to implement this method as part of your class. Forgetting to do that you would get an error or you are required to declare your class an abstract class as well. You could not instantiate an object from an abstract class. Extending your classes from JsonFriendly is the recommended way, because it prevents you from accidentally forgetting to implement the required method mentioned above, or implementing it with wrong name.

Here is an example of using the above class which is json friendly:

>>> o = DerivedJsonFriendly(3,4)
>>> json.dumps(o)
'{"field1": 3, "field2": 4}'

Example 3: Not Deriving from JsonFriendly but not failing json.dumps

if you have already imported JsonFriendly in your code, then any object containing as_json_friendly_obj method will work properly with json.dumps. Here is an example:

class NonDerivedJsonFriendly:
    def __init__(self, field1, field2):
        self._field1 = field1
        self._field2 = field2

    def _as_json_friendly_obj(self):
        return {"field1": self._field1, "field2": self._field2}

Now if you use an object of this class you will get:

>>> o = NonDerivedJsonFriendly(5, 6)


>>> # The following command would fail because we have not yet imported JsonFriendly
... json.dumps(o)  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mabouali/miniconda3/envs/PyJsonFriendly/lib/python3.7/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/Users/mabouali/miniconda3/envs/PyJsonFriendly/lib/python3.7/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/Users/mabouali/miniconda3/envs/PyJsonFriendly/lib/python3.7/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/Users/mabouali/miniconda3/envs/PyJsonFriendly/lib/python3.7/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type NonDerivedJsonFriendly is not JSON serializable


>>> from PyJsonFriendly import JsonFriendly
>>> # However, the following command will work just fine; because we have imported the JsonFriendly
... json.dumps(o)  
'{"field1": 5, "field2": 6}'

Although, this would work, however, you are not prompted/notified to implement _as_json_friendly_obj in your class. And if you forget to implement that function then passing your object to json.dumps will lead to raising a TypeError exception. Also you could not use the isinstance method to successfully check if you could pass your object to json.dumps:

>>> o1 = DerivedJsonFriendly(3, 4)
>>> o2 = NonDerivedJsonFriendly(5, 6)
>>> isinstance(o1,PyJsonFriendly)
True
>>> isinstance(o2,PyJsonFriendly)
False

Although, you could still use hasattr method, but this is not so appealing:

>>> hasattr(o1, "_as_json_friendly_obj")
True
>>> hasattr(o2, "_as_json_friendly_obj")
True

Example 4: Making objects JsonFriendly during the runtime

What if you are not the author of the object; however, you want to make them JsonFriendly? Python allows you to amend the class definition during the runtime. Check the following example:

>>> from PyJsonFriendly import JsonFriendly
>>> o = NotJsonFriendly(7, 8)
>>> # Any Attempt to use json.dumps(o) will fail. Because o is not JsonFriendly and
... # does not implement _as_json_friendly_obj
... # Let's modify the object though during the runtime:
... o.__class__._as_json_friendly_obj = lambda _: {"field1": _._field1, "field2": _._field2}
>>> json.dumps(o)
'{"field1": 7, "field2": 8}'

Example 5: _as_json_friendly_obj does not need to return a dictionary

Note that _as_json_friendly_obj does not need to return a dictionary. You could return anything that python's json accepts. For a table showing the objects that are accepted by json package by default click here. The following is an example:

from PyJsonFriendly import JsonFriendly
class JsonFriendlyNoneDictOutput(JsonFriendly):
    def __init__(self, field1, field2):
        self._field1 = field1
        self._field2 = field2

    def _as_json_friendly_obj(self):
        return [self._field1, self._field2]

This would also work as follows:

>>> o = JsonFriendlyNoneDictOutput(9, 10)
>>> json.dumps(o)
'[9, 10]'

Bonuses

JSON Friendly Numpy NDArray

Calling json.dumps on a numpy.ndarray would result into failure.

>>> np_arr = np.asarray([1, 2, 3, 4])
>>> json.dumps(np_arr)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "E:\ProgramData\Anaconda3\envs\PyJsonFriendly\lib\json\__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "E:\ProgramData\Anaconda3\envs\PyJsonFriendly\lib\json\encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "E:\ProgramData\Anaconda3\envs\PyJsonFriendly\lib\json\encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "E:\ProgramData\Anaconda3\envs\PyJsonFriendly\lib\json\encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type ndarray is not JSON serializable

If for whatever reason, you are interested to turn your numpy.ndarray into a json friendly, all you need to do is import PyJsonFriendly.JsonFriendlyNumpyNDArray, as follow:

import PyJsonFriendly.JsonFriendlyNumpyNDArray
>>> json.dumps(np_arr)
'{"type": "np.ndarray", "dtype": "int32", "shape": [4], "size": 4, "data": [1, 2, 3, 4]}'


>>> np_arr = np_arr.reshape((2,2))
>>> json.dumps(np_arr)
'{"type": "np.ndarray", "dtype": "int32", "shape": [2, 2], "size": 4, "data": [[1, 2], [3, 4]]}'

Release files for PyJsonFriendly 19.11.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for PyJsonFriendly 19.11.0
File Size Uploaded
PyJsonFriendly-19.11.0.tar.gz 5.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for PyJsonFriendly 19.11.0
File Interpreter ABI Platform
PyJsonFriendly-19.11.0-py3-none-any.whl Python 3 none any Details

Total release size: 15.7 kB

Release files / PyJsonFriendly-19.11.0.tar.gz

Download URL PyJsonFriendly-19.11.0.tar.gz
Size 5.0 kB
Tags Source
SHA-256 checksum
How to use checksums
595030f5583afe5b94bc1f6cea28c8a167eca034aff1025bf9b2a892e0712de9
BLAKE2b-256 checksum
How to use checksums
7a17797780be95cc9052a1b471620e32778b1fe747cc64ba76aa291f29215a04
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/2.0.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.6.0 requests-toolbelt/0.9.1 tqdm/4.37.0 CPython/3.7.5

Release files / PyJsonFriendly-19.11.0-py3-none-any.whl

Download URL PyJsonFriendly-19.11.0-py3-none-any.whl
Size 10.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c56ada4eba173a510e14bb884c8464e92a013f27411261af33c514a5fb4bb97a
BLAKE2b-256 checksum
How to use checksums
787890c3cfc495ecc43a4e45048ef5a5e2de4e572e128b19382445ae167a557a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/2.0.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.6.0 requests-toolbelt/0.9.1 tqdm/4.37.0 CPython/3.7.5

Release history Release notifications | RSS feed

This release

19.11.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page