-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Python][test] oneOf with overlapping types #6674
[Python][test] oneOf with overlapping types #6674
Conversation
modules/openapi-generator/src/test/resources/3_0/oneOfOverlapingTypes.yaml
Outdated
Show resolved
Hide resolved
aecc499
to
40b0ab4
Compare
samples/openapi3/client/features/python-experimental/one_of/one_of/model/fruit.py
Outdated
Show resolved
Hide resolved
samples/openapi3/client/features/python-experimental/one_of/one_of/model/fruit.py
Outdated
Show resolved
Hide resolved
samples/openapi3/client/features/python-experimental/one_of/one_of/model/fruit.py
Outdated
Show resolved
Hide resolved
samples/openapi3/client/features/one_of/python-experimental/one_of/model/fruit.py
Outdated
Show resolved
Hide resolved
samples/openapi3/client/features/one_of/python-experimental/one_of/model/fruit.py
Outdated
Show resolved
Hide resolved
Thank you for the explanation. This is similar to a problem that was also identified in Java jersey2. AFAIK, in case of composed schemas, the following use cases are not currently handled:
The problem exists for When two properties with the same name are specified, afaik the "last one wins", i.e. the last referenced schema in the OAS document wins. the "last" property wins |
@@ -15,6 +15,12 @@ class {{unescapedDescription}}(ModelComposed): | |||
|
|||
{{> python-experimental/model_templates/classvars }} | |||
|
|||
{{#oneOf}} | |||
{{#-first}} | |||
attribute_map = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The correct solution would include all properties defined directly on the model and not in any oneOf
one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A composed schema can have properties at the base level and and can have oneOf defined. To cover that case we do need to define attribute_map here. The composed schema is more strict and can require:
ComposedSchema:
properties:
someVar:
type: string
oneOf:
- Apple
And Apple will accept any type for someVar because it is accepted as an additionalProperty, but in ComposedSchema we need to check the type of someVar to make sure that it is type str in python.
We can also have a schema like:
ComposedSchema:
allOf:
- Plant
oneOf:
- Apple
In which case the composed schema should also store the parameter names in the
attribute_map for Plan + Apple.
General question about when this problem arises.
Can't this happen for all of these cases for required + optional variables:
- oneOf schemas have a variable with conflicting type
- anyOf schemas have a variable of conflicting type
- Does our generator allow type collisions between variables in (allOf + oneOf) or (allOf + anyOf)? It should not, that violates the openapi spec.
You have also revealed that the docstring for this function is incorrect for these 1-3 use cases.
Python-experimental has previously addressed issues with composed schema inputs and tweaking them in the past with the method addNullDefaultToOneOfAnyOfReqProps. It goes through and sets composed schema required inputs to have a default null value in the composed schema init signature. This makes those inputs named arguments and makes them optional for users to pass them in. This is because:
we can have 2 oneOf schemas, schemaA, and schemaB each with 1 required variable, varA, varB. If we are only making an instance of schemaA, then varB is not required. So we set them all to null, and when we make an instance of schemaA, it requires that we pass in varA.
How about we do some similar tweaking at the composed schema variable level here?
We could
- look for variable type collisions in the oneOf/anyOf variables of a composed schema
- update their data types at the composed schema level to be a tuple of the allowed types
- this lets us keep using the mustache template as-is
- this keeps our documentation correct and lets our users know that multiple types can be passed in for these variables
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- oneOf schemas have a variable with conflicting type
This can happen and we should support it.
- anyOf schemas have a variable of conflicting type
It can happen. I am not sure how it should be resolved when a value matches multiple conflicting types.
- Does our generator allow type collisions between variables in (allOf + oneOf) or (allOf + anyOf)? It should not, that violates the openapi spec.
You are right that It should not.
I am not sure about the solution though. I would completely remove validation on base schema for properties defined in XOf models.
I agree that we should not merge this mustache template patch. I was looking for a quick solution that would unblock me so I can at least generate code that can deserialize server response without raising an exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does our generator allow type collisions between variables in (allOf + oneOf) or (allOf + anyOf)? It should not, that violates the openapi spec.
One can intentionally or accidentally write a OAS document which is 1) syntactically compliant with the JSON schema specification and 2) will not match any input payload. It's an interesting question whether it's even possible to analyze a schema and conclude whether there is at least one matching input data.
IMO this should be handled with the --validation
argument, and the code generator should still accept the OAS document. I.e. you want to know if a OAS doc is syntactically valid.
Consider pattern
. There is an infinite number of regex that will not match any input string, including the empty string. Here is one simple example:
type: string
pattern: .^
I have a quick update for templates that works for me ™️. I could not find out how to get directly defined properties on the model. |
My understanding is that this is the cause. In java the codegenmodel pools all variable inputs from all oneOf anyOf allOf models as inputs in the composed model. So we can have collisions. Maybe we should store plural types for CodegenParameter and CodegenProperty. What do you think @wing328 @jimschubert |
As a side note, the schema may be brittle if two |
For the record python-experimental handles this use case. |
Below is
I know, there is a much simpler way to write the schema, this is just an example to test the edge cases. TestOneOf:
oneOf:
- type: object
properties:
breed:
type: string
pattern: '[a-z]{1,10}'
- type: object
properties:
breed:
type: string
pattern: '[a-z]{11,20}' Here is the generated python code. class TestOneOf(ModelComposed):
validations = {
('breed',): {
'regex': {
# NOTE The last one wins. Doesn't that mean the generated code will always match the input data against this pattern?
'pattern': r'[a-z]{11,20}', # noqa: E501
},
},
} I'm not saying this breaks my use cases. |
Ah, my mistake python-experimental does not have this working yet. It looks like I need to combine or strip out oneOf and anyOf validations at the composed schema level. Then it should work. Thank you for pointing that out. |
...i-generator/src/main/resources/python/python-experimental/model_templates/classvars.mustache
Show resolved
Hide resolved
samples/openapi3/client/features/one-of/python-experimental/.travis.yml
Outdated
Show resolved
Hide resolved
I scanned through this, and I think the approach makes sense. Were there additional requests to be made before merge (@spacether and @sebastien-rosset)? There are a handful of proposed changes, were you wanting to change those before merge @jirikuncar ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mustache changes will break functionality for composed schemas that include properties.
The changes omit properties variables that are defined like this:
components:
schemas:
ComposedModelWithProperties:
properties:
- color:
type: string
oneOf:
- Cat
- Dog
Can you add an example like I have shown above and show that color is present in ComposedModelWithProperties.openapi_types?
- Could we fix this in composed schemas by just iterating over vars to make openapi_types?
- Are the properties only loaded into vars vs requredVars/optionalVars/allVars?
- How about also changing the validations in a composed schema to only iterate over those vars?
2c466aa
to
cd9f891
Compare
@jimschubert all changes has been resolved by upgrading to latest master. @spacether it looks like you have doing a big refactoring in #7274. I will wait until it's merged before adding more changes to this PR. |
cd9f891
to
e397768
Compare
Thank you for your patience. 7274 was just merged so you can continue work here. |
@spacether You'd requested changes on this PR. Do you have any remaining concerns? I'd like to get it in before addition conflicts emerge. |
Yes, my change requested comment still applies.
Iterating over vars should handle all of these above use case and prevent type conflicts if vars only contains the vars from composed schema properties. To do this, in modules/openapi-generator/src/main/resources/python/python-experimental/model_templates/model_composed.mustache |
FYI I am working on helping on this. I duplicated your branch and I am working on implementing my |
I am working on fixing this in two PRS:
|
Closing due to inactivity |
tl;dr Shows a serialization problem of
oneOf
models inpython-experimental
with overlapping types.Minimal specification
Two models with overlapping field definition of named enum type.
Problem
The generated model contains all fields and the overlapping field has wrong type.
This prevents deserialization of
{"kind": "sweet", "color": "red"}
response.How do I get expected behavior?
Simply remove definition of
openapi_types
andattribute_map
and let theoneOf
models do the job.PR checklist
./bin/generate-samples.sh
to update all Petstore samples related to your fix. This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master. These must match the expectations made by your contribution. You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example./bin/generate-samples.sh bin/config/java*
. For Windows users, please run the script in Git BASH.master
cc @sebastien-rosset