tabpy.tabpy_tools.schema   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 109
Duplicated Lines 0 %

Test Coverage

Coverage 69.69%

Importance

Changes 0
Metric Value
wmc 9
eloc 36
dl 0
loc 109
ccs 23
cts 33
cp 0.6969
rs 10
c 0
b 0
f 0

2 Functions

Rating   Name   Duplication   Size   Complexity  
A generate_schema() 0 56 1
B _generate_schema_from_example_and_description() 0 42 8
1 1
import logging
2 1
import genson
3 1
import jsonschema
4
5
6 1
logger = logging.getLogger(__name__)
7
8
9 1
def _generate_schema_from_example_and_description(input, description):
10
    """
11
    With an example input, a schema is automatically generated that conforms
12
    to the example in json-schema.org. The description given by the users
13
    is then added to the schema.
14
    """
15 1
    s = genson.SchemaBuilder(None)
16 1
    s.add_object(input)
17 1
    input_schema = s.to_schema()
18
19 1
    if description is not None:
20 1
        if "properties" in input_schema:
21
            # Case for input = {'x':1}, input_description='not a dict'
22 1
            if not isinstance(description, dict):
23
                msg = f"{input} and {description} do not match"
24
                logger.error(msg)
25
                raise Exception(msg)
26
27 1
            for key in description:
28
                # Case for input = {'x':1},
29
                # input_description={'x':'x value', 'y':'y value'}
30 1
                if key not in input_schema["properties"]:
31
                    msg = f"{key} not found in {input}"
32
                    logger.error(msg)
33
                    raise Exception(msg)
34
                else:
35 1
                    input_schema["properties"][key]["description"] = description[key]
36
        else:
37 1
            if isinstance(description, dict):
38
                raise Exception(f"{input} and {description} do not match")
39
            else:
40 1
                input_schema["description"] = description
41
42 1
    try:
43
        # This should not fail unless there are bugs with either genson or
44
        # jsonschema.
45 1
        jsonschema.validate(input, input_schema)
46
    except Exception as e:
47
        logger.error(f"Internal error validating schema: {str(e)}")
48
        raise
49
50 1
    return input_schema
51
52
53 1
def generate_schema(input, output, input_description=None, output_description=None):
54
    """
55
    Generate schema from a given sample input and output.
56
    A generated schema can be passed to a server together with a function to
57
    annotate it with information about input and output parameters, and
58
    examples thereof. The schema needs to follow the conventions of JSON Schema
59
    (see json-schema.org).
60
61
    Parameters
62
    -----------
63
    input : any python type | dict
64
    output: any python type | dict
65
    input_description : str | dict, optional
66
    output_description : str | dict, optional
67
68
    References
69
    -----------
70
    - `Json Schema <http://json-schema.org/documentation.html>`
71
72
    Examples
73
    ----------
74
    .. sourcecode:: python
75
        For just one input parameter, state the example directly.
76
        >>> from tabpy.tabpy_tools.schema import generate_schema
77
        >>> schema = generate_schema(
78
                              input=5,
79
                              output=25,
80
                              input_description='input value',
81
                              output_description='the squared value of input')
82
        >>> schema
83
        {'sample': 5,
84
         'input': {'type': 'integer', 'description': 'input value'},
85
         'output': {'type': 'integer', 'description': 'the squared value of input'}}
86
        For two or more input parameters, specify them using a dictionary.
87
        >>> import graphlab
88
        >>> schema = generate_schema(
89
                  input={'x': 3, 'y': 2},
90
                  output=6,
91
                  input_description={'x': 'value of x',
92
                                 'y': 'value of y'},
93
              output_description='x times y')
94
        >>> schema
95
        {'sample': {'y': 2, 'x': 3},
96
         'input': {'required': ['x', 'y'],
97
                   'type': 'object',
98
                   'properties': {'y': {'type': 'integer', 'description': 'value of y'},
99
                                  'x': {'type': 'integer', 'description': 'value of x'}}},
100
         'output': {'type': 'integer', 'description': 'x times y'}}
101
    """  # noqa: E501
102 1
    input_schema = _generate_schema_from_example_and_description(
103
        input, input_description
104
    )
105 1
    output_schema = _generate_schema_from_example_and_description(
106
        output, output_description
107
    )
108
    return {"input": input_schema, "sample": input, "output": output_schema}
109