简体   繁体   中英

Python serialize a class and change property casing using JsonPickle

With Python and JsonPickle, How do I serialize the object with a Certain Casing, eg Camel Case, Pascal, etc? The following answer below does it manually, however looking for a specific Jsonpickle solution, since it can handle complex object types.

JSON serialize a class and change property casing with Python

https://stackoverflow.com/a/8614096/15435022

class HardwareSystem:
    def __init__(self, vm_size):
        self.vm_size = vm_size
        self.some_other_thing = 42
        self.a = 'a'

def snake_to_camel(s):
    a = s.split('_')
    a[0] = a[0].lower()
    if len(a) > 1:
        a[1:] = [u.title() for u in a[1:]]
    return ''.join(a)

def serialise(obj):
    return {snake_to_camel(k): v for k, v in obj.__dict__.items()}

hp = HardwareSystem('Large')
print(json.dumps(serialise(hp), indent=4, default=serialise))

Here's my attempt.

from importlib import import_module
import inspect
import json
import jsonpickle
import re


def snake_to_camel(s):
    a = s.split('_')
    a[0] = a[0].lower()
    if len(a) > 1:
        a[1:] = [u.title() for u in a[1:]]
    return ''.join(a)

def camel_to_snake(s):
    snake = []
    snake_len = len(s)
    for idx, char in enumerate(s):
        snake.append(char.lower())
        if idx < snake_len - 1:
            if char.islower() and s[idx+1].isupper():
                snake.append('_')
    return ''.join(snake)

def debug_output(obj):
    output = '{}({})'
    attrs = [attr + '=' + repr(getattr(obj, attr)) for attr in vars(obj)]
    return output.format(obj.__class__.__name__, ', '.join(attrs))


class SoftwareSystem:
    def __init__(self):
        self.software_rating = 'Awesome!'
    
    # Making debug output friendly
    def __repr__(self):
        return debug_output(self)


class HardwareSystem:
    def __init__(self, vm_size):
        self.vm_size = vm_size
        self.some_other_thing = 42
        self.a = 'a'
    
    # Making debug output friendly
    def __repr__(self):
        return debug_output(self)


@jsonpickle.handlers.register(HardwareSystem, base=True)
@jsonpickle.handlers.register(SoftwareSystem, base=True)
class SystemHandler(jsonpickle.handlers.BaseHandler):
    def flatten(self, obj, data):
        for k, v in obj.__dict__.items():
            data[snake_to_camel(k)] = jsonpickle.encode(v)
        return data

    def restore(self, obj):
        # Gets reference to class
        # https://stackoverflow.com/a/55559852/152016
        module_path, class_name = obj['py/object'].rsplit('.', 1)
        module = import_module(module_path)
        class_ = getattr(module, class_name)

        # Dealing with __init__ params (except first)
        params = inspect.getargs(class_.__init__.__code__)
        params = params.args[1:]

        # Preparing dict keys
        l_obj = {}
        for k, v in obj.items():
            l_obj[camel_to_snake(k)] = v

        # Instantiating constructor params
        data = {}
        for k, v in l_obj.items():
            if k in params:
                data[k] = v 
        result = class_(**data)

        # Setting other jsonpickled object attributes 
        for k, v in l_obj.items():
            if not k in params:
                setattr(result, k, v)

        return result


hw = HardwareSystem(100)
sw = SoftwareSystem()
hw.software_instance = sw
json_str = jsonpickle.encode(hw)
print(json_str)
decoded = jsonpickle.decode(json_str)
print(hw)

This has some assumptions:

  • Following your original snake_to_camel function, I've put up a camel_to_snake on decoding, that assumes only the first uppercase letter after a lowercase letter will have prepended the _ char (so awesomeABC will translate to awesome_abc , and therefore if you translate it back again it will be incorrectly awesomeAbc )
  • The above code encodes/decodes properties added after __init__ (see for example hw.software_instance above).
  • You can nest objects. I've only tried a single object nested.
  • I've added auxiliary debug_output / __repr__ functions, you may throw these away (or customize:))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM