Serialization module (anvil-labs new feature)

Hi all,

We took some inspiration from posts:

Make portable objects saveable

The order of keys in a dictionary returned from a server function is changing mysteriously

Tuples transformed to lists in server call. Bug?

and developed a custom serialization module in anvil-labs.

We call it kompot
It wraps Anvil’s builtin serialziation mechanism.


Why use it:

  • store portable classes in simple object columns or in browser storage
  • dictionaries
    • maintain key order across server/client calls
    • arbitrary keys are supported, not just strings
  • tuples will remain tuples and won’t be converted to lists
  • set, frozenset are supported

API:

kompot.register used to register a portable class with kompot
kompot.call use in place of anvil.server.call
kompot.callable use in place of @anvil.server.callable
kompot.serialize use to serialize an object before sending to the server - kompot will leave things it doesn’t know how to serialize to anvil’s builtin in serialization e.g. (table rows, media objects, capabilities)
kompot.preserve like serialize but will throw a SerializationError if there are objects that kompot doesn’t know how to serialize. Use to store an object as JSON, as a simple object or in local storage
kompot.reconstruct reconstruct an object that was serialized by kompot

Example code

from anvil_labs import kompot

@anvil.server.portable_class
class Jar:
    def __init__(self, fruits: set):
        self.fruits = fruits

kompot.register(Jar)

jar = Jar({"apples", "pears"})
kompot.call("store", jar) # you can't normally send sets to the server
# SERVER
@kompot.callable
def store(jar):
    assert type(jar.fruits) is set

    as_simple_object = kompot.preserve(jar)
    row = app_tables.pantry.add_row(jar=as_simple_object)

    # if you want to get the jar back
    jar = kompot.reconstruct(row["jar"])

    return jar

Use of kompot.serialize

Instead of kompot.call and kompot.callable you can use serialize/reconstruct for specific arguments/return values being sent to and from the server/client

# Client side
anvil.server.call('save', kompot.serialize(jar))

# Server side
@anvil.server.call
def save(serialized_jar):
    jar = kompot.reconstruct(serialized_jar)
    ...

kompot.serialize is better than kompot.preserve here since any serializable objects that kompot doesn’t know how to serialize will be serialized by Anvil when making the server call.


How to use it

As ever - anvil labs remains experimental, but for those looking to experiment…
you can add anvil-labs as a third party dependency with the code
5YU7BBT6T5O7ZNOX


Documentation:

https://anvil-labs.readthedocs.io/en/latest/guides/modules/kompot.html

11 Likes

This is exciting. I was recently pondering trying to build something similar (but was doubtful I could efficiently figure out how to code the type-checking and crawling needed for the serialization). So thank you for beating me to it!

I did have a couple other ideas for features that I’ve added to the Issues section on GitHub: requiring authorization by default, and allowing multiple server function calls within a single round trip to the server.

1 Like

Wow, just like that, @stucork turned one of my vague ideas into elegant, working code. Now you can batch multiple server functions within a single round trip to the server–without writing an additional, bespoke server function. Instead, client-side, you can just write:

with kompot.batch_call() as c:
    c.call('foo', x=1)
    c.call('bar', 42)

foo_result, bar_result = c.result
6 Likes