not json serializable [solved]

Need help, or want to share a macro? Post here!
User avatar
iplayfast
Posts: 47
Joined: Sat Sep 07, 2019 6:55 am

not json serializable [solved]

Postby iplayfast » Mon Nov 11, 2019 8:17 am

Trying to save my cycloidal gear https://github.com/iplayfast/CycloidGearBox and the json encoder seems to not like it.
I'm sure it's something I'm doing in my code, but I really don't know what.

Anybody have ideas how to debug this?

Code: Select all

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

OS: Linux Mint 19.2 (X-Cinnamon/cinnamon)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.19.18694 (Git) AppImage
Build type: Release
Branch: master
Hash: c3ba04183e016e15410d84bae4d00556d22c7da5
Python version: 3.7.3
Qt version: 5.12.5
Coin version: 4.0.0a
OCC version: 7.3.0
Locale: English/Canada (en_CA)
Last edited by iplayfast on Mon Nov 11, 2019 7:20 pm, edited 1 time in total.
Bayesian
Posts: 57
Joined: Thu Aug 08, 2019 1:49 pm

Re: not json serializable

Postby Bayesian » Mon Nov 11, 2019 4:27 pm

You could try to use different parameters and see if they work. Otherwise it's a bug with that particular script.

In any case, take a look at the object's properties and double-check they are proper FC properties. Those should be json serializable with very few exceptions.

I remember reading somewhere FC started out serializing Python objects with cpickle, but now uses JSON. You might have to change some property or class member to something that works for json. I don't think you can customize the serializer.
User avatar
DeepSOIC
Posts: 7145
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: not json serializable

Postby DeepSOIC » Mon Nov 11, 2019 4:34 pm

implement __getstate__(self) and __setstate__(self,state) of all your proxy object classes. Empty implementation is usually what is needed.
User avatar
DeepSOIC
Posts: 7145
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: not json serializable

Postby DeepSOIC » Mon Nov 11, 2019 4:44 pm

more on that.

Code: Select all

class   pindiskClass():
    def __init__(self,obj,cgb):
        self.Object = obj
        self.cgb = cgb
        ...
        self.ShapeColor=(0.67,0.68,0.88)
If you do the empty getstate, setstate, all these assignments will be lost after save/load cycle, your proxy object will have no attributes. __init__ is not called when loading an object from a file. What is called is onDocumentRestored(self, obj). This is a good place to reconstruct your attributes if you need them.

I usually don't put any attributes into proxy objects, and simply save all I need as properties of obj.
User avatar
iplayfast
Posts: 47
Joined: Sat Sep 07, 2019 6:55 am

Re: not json serializable

Postby iplayfast » Mon Nov 11, 2019 5:45 pm

Thanks DeepSOIC,
I'm not following you. Are you are saying, don't use empty get/set state function because the assignments will be lost, so instead I should add a function called onDocumentRestored?

I'm new to FreeCAD, and not an expert in python, so I think you might be assuming that I know what you are talking about :)
User avatar
DeepSOIC
Posts: 7145
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: not json serializable

Postby DeepSOIC » Mon Nov 11, 2019 6:45 pm

iplayfast wrote:
Mon Nov 11, 2019 5:45 pm
...
well, it's quite difficult to explain all that.

See how to store attributes with getstate/setstate here: Creating_a_FeaturePython_Box,_Part_II

Code: Select all

class box():

   def __init__(self, obj):
       """
       Default Constructor
       """

       self.Type = 'box' # <----------- !!
       self.ratios = None

       obj.addProperty('App::PropertyString', 'Description', 'Base', 'Box description').Description = 'Hello World!'
       obj.addProperty('App::PropertyLength', 'Length', 'Dimensions', 'Box length').Length = 10.0
       obj.addProperty('App::PropertyLength', 'Width', 'Dimensions', 'Box width'). Width = '10 mm'
       obj.addProperty('App::PropertyLength', 'Height', 'Dimensions', 'Box Height').Height = '1 cm'
       obj.addProperty('App::PropertyBool', 'Aspect Ratio', 'Dimensions', 'Lock the box aspect ratio').Aspect_Ratio = False

       obj.Proxy = self
       self.Object = obj

   def __getstate__(self):
       return self.Type # <----------- !!

   def __setstate__(self, state):
       if state:
           self.Type = state # <----------- !!
 
   
Note that self.Object is not participating in getstate/setstate. It isn't, because it is not JSON-serializable (and even if it was, the result will not be useful). By default (if no __getstate__ and __setstate methods are defined), FreeCAD tries to serialize all the attributes of your object, including .Object. That is what causes your errors.
User avatar
iplayfast
Posts: 47
Joined: Sat Sep 07, 2019 6:55 am

Re: not json serializable

Postby iplayfast » Mon Nov 11, 2019 7:19 pm

Thank you. I think I get it, (and it works).
Icons aren't loading but I think that's a different problem.
cron