holoviz / holoviz/param

JSON schema generation incomplete

Open
#524 1 comment 0 reactions 2 assignees Claimed by @philippjfr View on GitHub
API
Dominant language
Python
Stars
521
Forks
86
Avg merge
1d 13h
Merged PRs (30d)
35

Description

At the moment, Param's JSON schema support is meant to work like this:

```python
import param, json, jsonschema

class P(param.Parameterized):
a = param.Integer(default=5, doc='Int', bounds=(2,30), inclusive_bounds=(True, False))
b = param.Number(default=4.3, allow_None=True)
c = param.String(default='foo')

p = P(a=29)
s = p.param.serialize_parameters()
d = json.loads(s)
full_schema = {"type" : "object", "properties" : p.param.schema()}
jsonschema.validate(instance=d, schema=full_schema)
```

I.e., `jsonschema.validate` accepts a python dictionary (the output of `json.loads(s)` on a string `s`) and a "full" schema (with "object" at the top level). This works, as you can see if you change one of the dictionary entries to something not matching the schema:

```python
d2 = d.copy()
d2.update(dict(a='astring'))

with param.exceptions_summarized():
jsonschema.validate(instance=d2, schema=full_schema)
```

```bash
ValidationError: 'astring' is not of type 'integer'
```

However, the validation also "succeeds" in many other cases that one would think would be validation errors:

```python
jsonschema.validate(instance=d2, schema=p.param.schema())
jsonschema.validate(instance=s, schema=p.param.schema())
jsonschema.validate(instance=42, schema=p.param.schema())
jsonschema.validate(instance="garbage", schema=p.param.schema())
```

I.e., if you pass not a full schema but the partial schema produced by `p.param.schema()`, `jsonschema.validate` will happily accept `d2`, or `s`, or pretty much anything you supply (e.g. the string "garbage" or an integer). All of these are rejected correctly if you pass `full_schema`.

Thus things only work properly when you pass `full_schema`, and worse, without `full_schema` they fail silently, which is likely to mislead users into thinking their input is valid when it is not.

Given the awkwardness of having to construct `full_schema` by hand, and the misleading output when using anything else, one might reasonably ask why `p.param.schema()` is not simply generating `full_schema` all the time, both for convenience and to ensure good validation in cases where the programmer is (reasonably) confused.

According to @jlstevens, he was reluctant to generate a `full_schema` directly because such an object represents a [JavaScript "object" type](https://www.w3schools.com/js/js_objects.asp), roughly corresponding to a Python dictionary, whereas here we are representing a Python class instance, which _has_ a dictionary but is not identical to a dictionary. Still, given the clear need to represent full Parameterized objects in JSON (see #520), plus the inconvenience of pasting on the `full_schema` boilerplate for the schema to be used with `jsonschema.validate`, plus the highly misleading behavior when supplying anything less than the `full_schema`, I strongly vote for `p.param.schema()` to return the equivalent of `full_schema` directly in all cases.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.