Skip to content

Commit

Permalink
[Python-experimental] Documentation enhancement for oneOf schema and …
Browse files Browse the repository at this point in the history
…minor err msg improvement (OpenAPITools#5791)

* Add documentation to generated code

* Improve error message

* Improve documentation

* Improve documentation

* Improve documentation

* Improve documentation

* Improve documentation

* Improve documentation

* Run sample scripts

* Address review comments

* Address review comments

* Fix problem in python error message
  • Loading branch information
sebastien-rosset authored and michaelpro1 committed May 7, 2020
1 parent 823c35b commit 734981b
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,11 @@ def get_required_type_classes(required_types_mixed):
def change_keys_js_to_python(input_dict, model_class):
"""
Converts from javascript_key keys in the input_dict to python_keys in
the output dict using the mapping in model_class
the output dict using the mapping in model_class.
If the input_dict contains a key which does not declared in the model_class,
the key is added to the output dict as is. The assumption is the model_class
may have undeclared properties (additionalProperties attribute in the OAS
document).
"""

output_dict = {}
Expand Down Expand Up @@ -936,19 +940,39 @@ def get_allof_instances(self, model_args, constant_args):

# and use it to make the instance
kwargs.update(constant_args)
allof_instance = allof_class(**kwargs)
composed_instances.append(allof_instance)
try:
allof_instance = allof_class(**kwargs)
composed_instances.append(allof_instance)
except Exception as ex:
raise ApiValueError(
"Invalid inputs given to generate an instance of '%s'. The "
"input data was invalid for the allOf schema '%s' in the composed "
"schema '%s'. Error=%s" % (
allof_class.__class__.__name__,
allof_class.__class__.__name__,
self.__class__.__name__,
str(ex)
)
)
return composed_instances


def get_oneof_instance(self, model_args, constant_args):
"""
Find the oneOf schema that matches the input data (e.g. payload).
If exactly one schema matches the input data, an instance of that schema
is returned.
If zero or more than one schema match the input data, an exception is raised.
In OAS 3.x, the payload MUST, by validation, match exactly one of the
schemas described by oneOf.
Args:
self: the class we are handling
model_args (dict): var_name to var_value
used to make instances
The input data, e.g. the payload that must match a oneOf schema
in the OpenAPI document.
constant_args (dict): var_name to var_value
used to make instances
args that every model requires, including configuration, server
and path to item.

Returns
oneof_instance (instance/None)
Expand All @@ -957,12 +981,17 @@ def get_oneof_instance(self, model_args, constant_args):
return None

oneof_instances = []
# Iterate over each oneOf schema and determine if the input data
# matches the oneOf schemas.
for oneof_class in self._composed_schemas()['oneOf']:
# transform js keys to python keys in fixed_model_args
# transform js keys from input data to python keys in fixed_model_args
fixed_model_args = change_keys_js_to_python(
model_args, oneof_class)

# extract a dict of only required keys from fixed_model_args
# Extract a dict with the properties that are declared in the oneOf schema.
# Undeclared properties (e.g. properties that are allowed because of the
# additionalProperties attribute in the OAS document) are not added to
# the dict.
kwargs = {}
var_names = set(oneof_class.openapi_types().keys())
for var_name in var_names:
Expand All @@ -982,14 +1011,14 @@ def get_oneof_instance(self, model_args, constant_args):
pass
if len(oneof_instances) == 0:
raise ApiValueError(
"Invalid inputs given to generate an instance of %s. Unable to "
"make any instances of the classes in oneOf definition." %
"Invalid inputs given to generate an instance of %s. None "
"of the oneOf schemas matched the input data." %
self.__class__.__name__
)
elif len(oneof_instances) > 1:
raise ApiValueError(
"Invalid inputs given to generate an instance of %s. Multiple "
"oneOf instances were generated when a max of one is allowed." %
"oneOf schemas matched the inputs, but a max of one is allowed." %
self.__class__.__name__
)
return oneof_instances[0]
Expand Down Expand Up @@ -1035,8 +1064,8 @@ def get_anyof_instances(self, model_args, constant_args):
pass
if len(anyof_instances) == 0:
raise ApiValueError(
"Invalid inputs given to generate an instance of %s. Unable to "
"make any instances of the classes in anyOf definition." %
"Invalid inputs given to generate an instance of %s. None of the "
"anyOf schemas matched the inputs." %
self.__class__.__name__
)
return anyof_instances
Expand Down Expand Up @@ -1087,10 +1116,18 @@ def get_unused_args(self, composed_instances, model_args):

def validate_get_composed_info(constant_args, model_args, self):
"""
For composed schemas/classes, validates the classes to make sure that
they do not share any of the same parameters. If there is no collision
then composed model instances are created and returned tot the calling
self model
For composed schemas, generate schema instances for
all schemas in the oneOf/anyOf/allOf definition. If additional
properties are allowed, also assign those properties on
all matched schemas that contain additionalProperties.
Openapi schemas are python classes.

Exceptions are raised if:
- no oneOf schema matches the model_args input data
- > 1 oneOf schema matches the model_args input data
- > 1 oneOf schema matches the model_args input data
- no anyOf schema matches the model_args input data
- any of the allOf schemas do not match the model_args input data

Args:
constant_args (dict): these are the args that every model requires
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,11 @@ def get_required_type_classes(required_types_mixed):
def change_keys_js_to_python(input_dict, model_class):
"""
Converts from javascript_key keys in the input_dict to python_keys in
the output dict using the mapping in model_class
the output dict using the mapping in model_class.
If the input_dict contains a key which does not declared in the model_class,
the key is added to the output dict as is. The assumption is the model_class
may have undeclared properties (additionalProperties attribute in the OAS
document).
"""

output_dict = {}
Expand Down Expand Up @@ -1192,19 +1196,39 @@ def get_allof_instances(self, model_args, constant_args):

# and use it to make the instance
kwargs.update(constant_args)
allof_instance = allof_class(**kwargs)
composed_instances.append(allof_instance)
try:
allof_instance = allof_class(**kwargs)
composed_instances.append(allof_instance)
except Exception as ex:
raise ApiValueError(
"Invalid inputs given to generate an instance of '%s'. The "
"input data was invalid for the allOf schema '%s' in the composed "
"schema '%s'. Error=%s" % (
allof_class.__class__.__name__,
allof_class.__class__.__name__,
self.__class__.__name__,
str(ex)
)
)
return composed_instances


def get_oneof_instance(self, model_args, constant_args):
"""
Find the oneOf schema that matches the input data (e.g. payload).
If exactly one schema matches the input data, an instance of that schema
is returned.
If zero or more than one schema match the input data, an exception is raised.
In OAS 3.x, the payload MUST, by validation, match exactly one of the
schemas described by oneOf.
Args:
self: the class we are handling
model_args (dict): var_name to var_value
used to make instances
The input data, e.g. the payload that must match a oneOf schema
in the OpenAPI document.
constant_args (dict): var_name to var_value
used to make instances
args that every model requires, including configuration, server
and path to item.
Returns
oneof_instance (instance/None)
Expand All @@ -1213,12 +1237,17 @@ def get_oneof_instance(self, model_args, constant_args):
return None

oneof_instances = []
# Iterate over each oneOf schema and determine if the input data
# matches the oneOf schemas.
for oneof_class in self._composed_schemas()['oneOf']:
# transform js keys to python keys in fixed_model_args
# transform js keys from input data to python keys in fixed_model_args
fixed_model_args = change_keys_js_to_python(
model_args, oneof_class)

# extract a dict of only required keys from fixed_model_args
# Extract a dict with the properties that are declared in the oneOf schema.
# Undeclared properties (e.g. properties that are allowed because of the
# additionalProperties attribute in the OAS document) are not added to
# the dict.
kwargs = {}
var_names = set(oneof_class.openapi_types().keys())
for var_name in var_names:
Expand All @@ -1238,14 +1267,14 @@ def get_oneof_instance(self, model_args, constant_args):
pass
if len(oneof_instances) == 0:
raise ApiValueError(
"Invalid inputs given to generate an instance of %s. Unable to "
"make any instances of the classes in oneOf definition." %
"Invalid inputs given to generate an instance of %s. None "
"of the oneOf schemas matched the input data." %
self.__class__.__name__
)
elif len(oneof_instances) > 1:
raise ApiValueError(
"Invalid inputs given to generate an instance of %s. Multiple "
"oneOf instances were generated when a max of one is allowed." %
"oneOf schemas matched the inputs, but a max of one is allowed." %
self.__class__.__name__
)
return oneof_instances[0]
Expand Down Expand Up @@ -1291,8 +1320,8 @@ def get_anyof_instances(self, model_args, constant_args):
pass
if len(anyof_instances) == 0:
raise ApiValueError(
"Invalid inputs given to generate an instance of %s. Unable to "
"make any instances of the classes in anyOf definition." %
"Invalid inputs given to generate an instance of %s. None of the "
"anyOf schemas matched the inputs." %
self.__class__.__name__
)
return anyof_instances
Expand Down Expand Up @@ -1343,10 +1372,18 @@ def get_unused_args(self, composed_instances, model_args):

def validate_get_composed_info(constant_args, model_args, self):
"""
For composed schemas/classes, validates the classes to make sure that
they do not share any of the same parameters. If there is no collision
then composed model instances are created and returned tot the calling
self model
For composed schemas, generate schema instances for
all schemas in the oneOf/anyOf/allOf definition. If additional
properties are allowed, also assign those properties on
all matched schemas that contain additionalProperties.
Openapi schemas are python classes.
Exceptions are raised if:
- no oneOf schema matches the model_args input data
- > 1 oneOf schema matches the model_args input data
- > 1 oneOf schema matches the model_args input data
- no anyOf schema matches the model_args input data
- any of the allOf schemas do not match the model_args input data
Args:
constant_args (dict): these are the args that every model requires
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,11 @@ def get_required_type_classes(required_types_mixed):
def change_keys_js_to_python(input_dict, model_class):
"""
Converts from javascript_key keys in the input_dict to python_keys in
the output dict using the mapping in model_class
the output dict using the mapping in model_class.
If the input_dict contains a key which does not declared in the model_class,
the key is added to the output dict as is. The assumption is the model_class
may have undeclared properties (additionalProperties attribute in the OAS
document).
"""

output_dict = {}
Expand Down Expand Up @@ -1192,19 +1196,39 @@ def get_allof_instances(self, model_args, constant_args):

# and use it to make the instance
kwargs.update(constant_args)
allof_instance = allof_class(**kwargs)
composed_instances.append(allof_instance)
try:
allof_instance = allof_class(**kwargs)
composed_instances.append(allof_instance)
except Exception as ex:
raise ApiValueError(
"Invalid inputs given to generate an instance of '%s'. The "
"input data was invalid for the allOf schema '%s' in the composed "
"schema '%s'. Error=%s" % (
allof_class.__class__.__name__,
allof_class.__class__.__name__,
self.__class__.__name__,
str(ex)
)
)
return composed_instances


def get_oneof_instance(self, model_args, constant_args):
"""
Find the oneOf schema that matches the input data (e.g. payload).
If exactly one schema matches the input data, an instance of that schema
is returned.
If zero or more than one schema match the input data, an exception is raised.
In OAS 3.x, the payload MUST, by validation, match exactly one of the
schemas described by oneOf.
Args:
self: the class we are handling
model_args (dict): var_name to var_value
used to make instances
The input data, e.g. the payload that must match a oneOf schema
in the OpenAPI document.
constant_args (dict): var_name to var_value
used to make instances
args that every model requires, including configuration, server
and path to item.
Returns
oneof_instance (instance/None)
Expand All @@ -1213,12 +1237,17 @@ def get_oneof_instance(self, model_args, constant_args):
return None

oneof_instances = []
# Iterate over each oneOf schema and determine if the input data
# matches the oneOf schemas.
for oneof_class in self._composed_schemas()['oneOf']:
# transform js keys to python keys in fixed_model_args
# transform js keys from input data to python keys in fixed_model_args
fixed_model_args = change_keys_js_to_python(
model_args, oneof_class)

# extract a dict of only required keys from fixed_model_args
# Extract a dict with the properties that are declared in the oneOf schema.
# Undeclared properties (e.g. properties that are allowed because of the
# additionalProperties attribute in the OAS document) are not added to
# the dict.
kwargs = {}
var_names = set(oneof_class.openapi_types().keys())
for var_name in var_names:
Expand All @@ -1238,14 +1267,14 @@ def get_oneof_instance(self, model_args, constant_args):
pass
if len(oneof_instances) == 0:
raise ApiValueError(
"Invalid inputs given to generate an instance of %s. Unable to "
"make any instances of the classes in oneOf definition." %
"Invalid inputs given to generate an instance of %s. None "
"of the oneOf schemas matched the input data." %
self.__class__.__name__
)
elif len(oneof_instances) > 1:
raise ApiValueError(
"Invalid inputs given to generate an instance of %s. Multiple "
"oneOf instances were generated when a max of one is allowed." %
"oneOf schemas matched the inputs, but a max of one is allowed." %
self.__class__.__name__
)
return oneof_instances[0]
Expand Down Expand Up @@ -1291,8 +1320,8 @@ def get_anyof_instances(self, model_args, constant_args):
pass
if len(anyof_instances) == 0:
raise ApiValueError(
"Invalid inputs given to generate an instance of %s. Unable to "
"make any instances of the classes in anyOf definition." %
"Invalid inputs given to generate an instance of %s. None of the "
"anyOf schemas matched the inputs." %
self.__class__.__name__
)
return anyof_instances
Expand Down Expand Up @@ -1343,10 +1372,18 @@ def get_unused_args(self, composed_instances, model_args):

def validate_get_composed_info(constant_args, model_args, self):
"""
For composed schemas/classes, validates the classes to make sure that
they do not share any of the same parameters. If there is no collision
then composed model instances are created and returned tot the calling
self model
For composed schemas, generate schema instances for
all schemas in the oneOf/anyOf/allOf definition. If additional
properties are allowed, also assign those properties on
all matched schemas that contain additionalProperties.
Openapi schemas are python classes.
Exceptions are raised if:
- no oneOf schema matches the model_args input data
- > 1 oneOf schema matches the model_args input data
- > 1 oneOf schema matches the model_args input data
- no anyOf schema matches the model_args input data
- any of the allOf schemas do not match the model_args input data
Args:
constant_args (dict): these are the args that every model requires
Expand Down

0 comments on commit 734981b

Please sign in to comment.