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

Add support for custom encoders #124

Open
thedrow opened this issue Dec 2, 2013 · 34 comments
Open

Add support for custom encoders #124

thedrow opened this issue Dec 2, 2013 · 34 comments

Comments

@thedrow
Copy link

thedrow commented Dec 2, 2013

I need custom encoders because I'd like to integrate it with Django-Rest-Framework.
See encode/django-rest-framework#1255 for details.

@jskorpan
Copy link

jskorpan commented Dec 2, 2013

No it does not. It’s a major feature we envision for a possible future ujson 2.0
//JT

@thedrow
Copy link
Author

thedrow commented Dec 2, 2013

What exactly needs to be done in order to progress this further?

@jskorpan
Copy link

jskorpan commented Dec 2, 2013

A speedy method of identifying and specifying custom encoders has to be defined and implemented. I’ve done some thinking around this, either we just have one custom encoder function which all values are passed through or we could go more complex and have a Dict<pythonClass, handleFunc> data structure. This would also allow us to modularize some rather type specific encoders we currently have in the code which may or may not serialize data to everyone’s liking.

I also recall an issue with how we are able to handle custom handlers returning a type which is in term is valid JSON. I can’t remember the exact details but my conclusion was to do a rewamp of the encoder step to fully support this better, there was something fundamental.

//JT

@thedrow
Copy link
Author

thedrow commented Dec 2, 2013

Don't you think your API should be compatible with the standard json module?

@jskorpan
Copy link

jskorpan commented Dec 2, 2013

I suppose we should honor the “drop in replacement” as far as possible yes.
We could add the class -> func mapping as an internal API not visible externally or as an extension on top of the JSON module spec.

@thedrow
Copy link
Author

thedrow commented Dec 2, 2013

I need a class encoder in order to drop in ujson in DRF. See https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/utils/encoders.py#L15

@jskorpan jskorpan reopened this Apr 11, 2014
@jskorpan jskorpan added this to the 2.0 milestone Apr 11, 2014
@jskorpan
Copy link

Moving this into the possible 2.0 milestone for ujson

@thedrow
Copy link
Author

thedrow commented May 25, 2014

What's the status on this? How can I help make it happen?

@thedrow
Copy link
Author

thedrow commented Sep 11, 2014

ping?

@nburns
Copy link

nburns commented Nov 14, 2014

I would love to be able to use custom encoders 👍

@lepture
Copy link

lepture commented Mar 18, 2015

👍

1 similar comment
@suzaku
Copy link

suzaku commented Mar 18, 2015

👍

@Zuckonit
Copy link

@cilia
Copy link

cilia commented May 13, 2015

And it'd be nice to have support for 'default' handler: default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError.

@zllak
Copy link

zllak commented Jun 30, 2015

👍

2 similar comments
@faizandfurious
Copy link

👍

@minglecm
Copy link

minglecm commented Aug 6, 2015

👍

@cristianocca
Copy link

I would love this feature as well, ujson is still faster than python's json even after 2.7 which moved into C code. What I don't know, if enabling custom encoders will slow down serialization to a point where ujson is as fast (or slow) as default python 2.7 json encoder.
What bothers me the most, is that even if is implemented in C, it is still 3 times as slow as nodejs json serialization which is also implemented in C

@dobber1134
Copy link

👍

@nryoung
Copy link

nryoung commented Jan 12, 2016

And it'd be nice to have support for 'default' handler: default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError.

100% agree on this. I would love to switch over to ujson completely but ujson doesn't support nested iterable data types.

@mayerwin
Copy link

mayerwin commented Mar 3, 2016

👍👍👍 Please also support custom encoding of dictionary keys, not just values. This is missing in all the json libraries I have tried, for no good reasons IMHO (performance impact should be negligible for those who would not use it). ujson is currently the best I have found thanks to the __json__ attribute (though I believe a handler approach, as jsonpickle is doing for example, would allow a cleaner and more decoupled extensibility).

@gjuarezh
Copy link

gjuarezh commented Jul 1, 2016

add support please!!

@megahoy
Copy link

megahoy commented Oct 22, 2016

+1 for this issue
need this feature

@lvalladares
Copy link

This would be a really nice feature, actually im having to switch back to standard json because my dict has some custom classes objects

@jz1371
Copy link

jz1371 commented Jul 19, 2017

+1 for adding this feature 👍

@olalonde
Copy link

Is there a workaround for this? I need this since some of my dicts contain numpy floats.

@mitar
Copy link
Contributor

mitar commented Aug 22, 2017

So you saw that you can use __json__ method on an object to customize encoding to JSON of your values? See here example.

@olalonde
Copy link

olalonde commented Aug 22, 2017

Ah thanks @mitar . I still ended up writing this workaround since I don't always have control over the objects I'm jsonifying:

def is_iterable(x):
    try:
        iter(x)
        return True
    except TypeError:
        return False


def map_anything(x, fn):
    if isinstance(x, str):
        return fn(x)
    if isinstance(x, dict):
        return {k: map_anything(v, fn) for k, v in x.items()}
    if is_iterable(x):
        return [map_anything(ele, fn) for ele in x]
    return fn(x)


def prepare_for_json(val):
    if isinstance(val, numpy.int32):
        return int(val)
    if isinstance(val, numpy.int64):
        return int(val)
    if isinstance(val, numpy.number):
        return str(val)
    return val


def json(data, **kwargs):
    # cls not supported by ujson
    # https://github.com/esnme/ultrajson/issues/124
    return json_dumps(map_anything(data, prepare_for_json), **kwargs)

@jackton1
Copy link

jackton1 commented Apr 9, 2018

Modifying @olalonde suggestion can also use the DRF encoder.

def serializer_func_mapper(x, fn):
    if isinstance(x, six.text_type):
        return six.text_type(x)
    if isinstance(x, six.integer_types):
        return int(x)
    if isinstance(x, dict):
        return {k: serializer_func_mapper(v, fn) for k, v in x.items()}
    if is_iterable(x):
        return [serializer_func_mapper(item, fn) for item in x]
    return fn(x)

 def json(data, **kwargs):
        if data is None:
            return bytes()
        encoder = JSONEncoder().default
        return ujson.dumps(serializer_func_mapper(data, encoder))

@joranbeasley
Copy link

don't the solutions listed above here totally negate any benefit derived from ujson? I would suspect at this point you would see better timing just using normal json with a default argument

@dstromberg
Copy link

I'd like cls= as well. Or something like it.

@Jeepeo
Copy link

Jeepeo commented Apr 24, 2020

Well even 2.0.3 is released.. What about this milestone, forgotten?

@hugovk hugovk removed this from the 2.0 milestone Apr 24, 2020
@hugovk
Copy link
Member

hugovk commented Apr 24, 2020

I've removed it from the milestone.

@Jeepeo
Copy link

Jeepeo commented Apr 24, 2020

but still waiting tho ;)

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