Skip to content

Full JSON/YAML support for Param #520

Description

@jbednar

Param's JSON support is currently quite limited. It can serialize and deserialize all the basic Parameter types, including types matching the native JSON/JS types (Integer, Float, String, etc.), containers of such types (List, Dict, etc.), or Python/Param-specific types that need to be stored in a special format and then decoded back into Python types (Tuple, Array, DataFrame, etc.). However, there is not currently any support for storing or restoring:

  • the Parameterized type of the object being serialized (which the deserialization code currently needs to know beforehand)
  • nested Parameterized objects (Parameter values that are themselves Parameterized objects)
  • directly to or from YAML (which is a superset of JSON)

These limitations prevent this form of text serialization from being used as a general-purpose human-readable text format for specifying collections of Parameterized objects. Ideally, we'd be able to serialize a large and comprehensive class of objects to pass around as JSON (in a server context), and would be able to accept a hierarchical YAML file instantiating various Parameterized classes, each of which may contain arbitrarily nested other Parameterized objects also specified. Of course, JSON itself was not designed to represent Parameterized objects or even Python objects, nor does it include explicit mechanisms for extending the language (unlike XML). Possible ways around this:

  1. YAML does include custom-type support using !, and one approach is to support additional functionality when using YAML only (as described for e.g. pyyaml) that accepts a specified custom type and instantiates it. E.g.:
someobj:
  !custompackage.custommodule.CustomType 
    name: "My object"
    size: 7
    nestedobj:
      !custompackage.custommodule.CustomType2:
        name: "Nested object"
        desc: "str"
  1. Establish a convention using JSON (and thus accepted in YAML), e.g. using a dict containing a special keyword like __type that you hope is unlikely to occur by chance. For example, in JSON:
{"someobj": 
    {"name":"My object", "__type":"custompackage.custommodule.CustomType", "size": 7, "nestedobj": 
        {"name": "Nested object", "__type":"custompackage.custommodule.CustomType2", "desc": "str""}}}

or in YAML:

someobj: 
  name: "My object"
  __type: "custompackage.custommodule.CustomType"
  size: 7
  nestedobj:
    name: "Nested object"
    __type: "custompackage.custommodule.CustomType2"
    desc: "str"

(I could easily have gotten any of the syntax here confused, so please update it if you spot an error!)

I think the pros of option 1 are that it fully follows the YAML spec and is thus well defined with no reliance on heuristics, and that it's clear to a non-Python recipient of such a file that it requires some custom handling to parse the ! entries. The cons are that it won't be supported for JSON output.

The pros of option 2 are that it's supported for both JSON and YAML equivalently, and the cons would be that it relies on a heuristic that won't necessarily be evident to some non-Python code that tries to parse such objects, potentially leading to undetected errors and missing functionality.

Anyone have an option 3? I think we should go ahead with some option, in any case.

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions