JSONSchema2PoPo2 icon indicating copy to clipboard operation
JSONSchema2PoPo2 copied to clipboard

Support definitions the are only "anyOf"

Open cmilhaupt opened this issue 3 years ago • 2 comments

Given the following schema test_schema.json:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "test schema",
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "id": {
            "$ref": "#/definitions/Identified"
        }
    },
    "definitions": {
        "Identifier": {
            "anyOf": [
                {
                    "type": "string",
                    "pattern": "^[a-z][a-z0-9_]*$"
                },
                { "type": "boolean" }
            ]
        }
    }
}

Running sonschema2popo2 -o test.py test_schema.json produces the following error:

  File "/usr/lib/python3.10/site-packages/jsonschema2popo/jsonschema2popo.py", line 159, in process
    models_map[model.full_name_path] = model
AttributeError: 'NoneType' object has no attribute 'full_name_path'

Which I believe is due to the definition_parser() not recognizing objects that only have the key anyOf. I believe the fix here is to modify the template so all the _set* functions will just make an "or" check for each type in the array.

cmilhaupt avatar Jan 03 '22 23:01 cmilhaupt

How would you expect this to work?

What would the generated code look like?

The property id would need to be either a string or a boolean (or in theory, anything else could be expressed in the anyOf including complex types). Other languages may not even allow this, such as Java or Go.

Generally I don't think it is a good idea to be squishy on the schema (anyOf), be specific that you require a particular type. If you want a boolean, then make sure that you get a boolean.

If you want to implement this, I'd be happy to review a pull request which adds this functionality, but I don't think this is something that I'd add myself.

MikeDombo avatar Jan 04 '22 02:01 MikeDombo

For python I would expect the generated code to look something like:

    def _set_id(self, value):
        if value is not None and not isinstance(value, str) and not isinstance(value, bool):
            raise TypeError("id must be str or bool")
        self.__id = value

This extends to complex types as well and works in most dynamic lanuages. To be completely honest I didn't realize this tool supported other languages like Java or Go, so in the static language case you'd have to so something clever with UnionTypes and/or interfaces. I'm not interested in this case so I didn't consider it, but it's certainly possible.

Unfortunately, it's not my schema. I stripped out a lot of the unnecessary parts to isolate the issue but this comes from the Kaitai Struct YAML Specification which is a JSON schema for their DSL. I imagine there are a lot of other use cases where it could be useful to encode a definition as a union of types, so I'm not sure I'd agree that "anyOf" is really squishy any more than python already is.

I may take a second pass at that definition_parser() method and open a PR if I have some extra time!

cmilhaupt avatar Jan 04 '22 03:01 cmilhaupt