Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cannot pickle Decimal #244

Closed
JssDWt opened this issue Jan 20, 2019 · 6 comments
Closed

cannot pickle Decimal #244

JssDWt opened this issue Jan 20, 2019 · 6 comments

Comments

@JssDWt
Copy link

JssDWt commented Jan 20, 2019

jsonpickle serializes Decimal as null.

Steps to reproduce:

  • install jsonpickle 1.0 and simplejson 3.16.0 in a python 3.7 environment
  • execute the following code:
import jsonpickle
from decimal import Decimal
jsonpickle.set_preferred_backend('simplejson')
jsonpickle.set_encoder_options('simplejson', use_decimal=True)
print(jsonpickle.encode(Decimal('2.0'), unpicklable=False, warn=True))

This prints:

UserWarning: jsonpickle cannot pickle Decimal('2.0'): replaced with None
warnings.warn(msg)
null

@rafalkasa
Copy link

Please try https://stackoverflow.com/questions/54276418/jsonpickle-with-simplejson-backend-serializes-decimal-as-null

import jsonpickle
from decimal import Decimal

jsonpickle.set_preferred_backend('simplejson')
jsonpickle.set_encoder_options('simplejson', use_decimal=True)

class DecimalHandler(jsonpickle.handlers.BaseHandler):

    def flatten(self, obj, data):

        return obj.__str__() #Convert to json friendly format

jsonpickle.handlers.registry.register(Decimal, DecimalHandler)

class MyClass():
    def __init__(self, amount):
        self.amount = amount

    def to_json(self):
        return jsonpickle.dumps(self, unpicklable=False)

if __name__ == '__main__':
    obj = MyClass(Decimal('1.0'))
    print(obj.to_json())

@JssDWt
Copy link
Author

JssDWt commented Feb 5, 2019

This actually prints {"amount": "1.0"}, which is not what I want. I'd expect {"amount": 1.0}.
PS I'm the one who asked that question on SO.

@woutdenolf
Copy link

Why do you expect a float? If you are worried about rounding errors, shouldn't you expect a str? Converting to float defies the purpose of having Decimal in the first place:

from decimal import Decimal
string = '1.00000000000000000000000001'
decimal = Decimal(string)
assert str(decimal) == string  # OK
assert str(float(decimal)) == string  # NOK
assert float(decimal) == decimal  # NOK

@JssDWt
Copy link
Author

JssDWt commented Feb 27, 2019

I do not expect a float. I expect to create a json value as a number, not a string. json does not interpret the kind of number or the precision. Serializing as a string would cause hassle explaining to other clients they should interpret the string as a number, which is not what I want.
Simplejson is capable of doing what I want and serializes Decimal as a json number if use_decimal is True. I'd expect the same to happen when using jsonpickle with simplejson as a backend.
The example you provide is python specific, and does not have to do much with json numbers.

@davvid davvid closed this as completed in c30f3fa Feb 27, 2019
@davvid
Copy link
Member

davvid commented Feb 27, 2019

I provided an example in the stackoverflow thread demonstrating how to do this. Additionally, I added a new use_decimal mode to encode/dumps that avoids converting to null and allows simplejson to handle the value rather than getting handled by jsonpickle.

https://jsonpickle.readthedocs.io/en/latest/api.html#jsonpickle.pickler.encode

It sounds like your use case is pretty specific, so please see the S.O. thread for more details.

@JssDWt
Copy link
Author

JssDWt commented Feb 27, 2019

@davvid that is excellent. Thank you very much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants