wolverdude / GenSON

GenSON is a powerful, user-friendly JSON Schema generator built in Python.
MIT License
584 stars 64 forks source link

Enhancement: Add parameter to add description placeholders #64

Open zbalkan opened 2 years ago

zbalkan commented 2 years ago

Summary

Description might be needed for a JSON schema to add comments for developers. It should be an optional parameter as it is not the case for everyone.

Example

I created a POC project, not usable for production, that generates documentation for YML files. I add description property to any JSON property that has a type, so I can ignore arrays, etc. It recursively visits schema, as a dictionary, and adds description property if a value has type.

def generate_json_schema(inputPath: str, outputPath: str, useAnnotations: bool = False, verbose: bool = False) -> None:

    if (verbose):
        print("Loading JSON file from path: " + inputPath)

    jsonObj = json.load(open(inputPath))

    if (verbose):
        print("Generating schema")

    builder: SchemaBuilder = SchemaBuilder()
    builder.add_object(jsonObj)
    schema: dict = builder.to_schema()

    # Here comes the magic
    add_description_property(schema)  # type: ignore

    if (useAnnotations):
        schema["title"] = TITLE
        schema["description"] = DESCRIPTION

    with open(outputPath, 'w') as json_file:
        json.dump(schema, json_file, indent=4)

    if (verbose):
        print("Saved schema to path: " + outputPath)

def add_description_property(d: dict) -> None:
    if ("type" in d):
        d["description"] = "# Description title\n\nDescription placeholder with *bold* and _italic_ text. This is a `code snippet`."
    for key, value in d.items():
        if (type(value) == dict):
            add_description_property(value)
wolverdude commented 2 years ago

Thanks for the idea!

I'm a bit hesitant to add a specific keyword arg for this, but it may point to a more generic use case that we could support. I think maybe that use case is simply being able to iterate through all the nodes in a SchemaBuilder and modify them.

Naively, SchemaBuilder could have an __iter__() method that yields up each node in turn. However, node is stored as SchemaNode and SchemaStrategy instances, not as a dicts, and those classes aren't intended to touch user code, so they don't have a good API for inspection and manipulation.

Alternately, to_schema() could accept a callable and call it on each node in the schema right after it gets translated to a dict, which I think may be easier to work with. That said, it's a fairly cumbersome thing to add to the interface, and the same functionality can be easily implemented in user code using a recursive function like the one you created.

There is a tradeoff in complexity here, so I'd like to see several +1s on this issue before moving forward. If you have another thought on how your use case might be solved without too much burden on the interface, I'd love to hear it.