-
-
Notifications
You must be signed in to change notification settings - Fork 228
fix(parser): indirect and recursive reference resolution (v2) #419
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
fix(parser): indirect and recursive reference resolution (v2) #419
Conversation
ef4eebd
to
20d3b15
Compare
20d3b15
to
47adea9
Compare
2df1eb0
to
b445c09
Compare
b445c09
to
5980501
Compare
Jfi, the current way to detect recursion has false positives and thus do not works as expected |
@p1-ra Is there any work in this direction? I have OpenAPI where most of the schemas are referenced indirectly 😅 Why we cannot just create a model with empty properties for indirectly referenced schemas and fill it later when proceed by order? @dbanty What do you think about this way? Is it compatible with the other problems with references you mentonied in March? |
- return PropertyError(data=data, detail="Could not find reference in parsed models or enums"), schemas
+ return (
+ AnyProperty(
+ name=name,
+ required=required,
+ nullable=False,
+ default=None,
+ python_name=utils.PythonIdentifier(value=name, prefix=config.field_prefix),
+ ),
+ schemas,
+ ) That change in L422 parser/properties/init.py leads to generation of extra models for me that were absent before. |
@mtovts I was about to mention this PR in yours, but I see you already found it 😅. The bigger refactor I talked about previously is already done, it was a change that resulted in the This PR is definitely stale, I've neglected it a long time and now there are conflicts 😁 so if you make yours have no overlap with the existing forward-resolution support (either by taking out the old method or utilizing it) then I think yours replaces this one. |
If I understand correctly, this branch doesn't work as anticipated and there isn't a plan on picking it back up. So I'm going to close this for now. I still want to support better reference resolution overall, but my efforts are focused on a different, super-secret project right now 😬 |
This PR aims to resolve indirect reference resolution and recursive reference resolution #338; It is a rework of #329
The goal here was to avoid the use of any global object, but since we have to lazy resolve a model during its own construction we still need to somehow be able to reference it before it even exist. For that I'm using the following strategy:
First, I've update the Schemas model:
https://github.com/triaxtec/openapi-python-client/blob/c7da89e201c66caf123961afd76cd5a38b2fec88/openapi_python_client/parser/properties/schemas.py#L66-L71
Properties are now wrapped into an
_Holder
object which is mutable. The goal here is to be able to register a classes_by_reference toward an not existing Property model yet. That why it can contains anRecursiveReferenceInterupt
which is anPropertyError
that we will use later during the ModelProperty parsing to create a specific lazy reference Property.To be able to detected recursive reference during schema update from OAI data, I'm tracking all already visited reference path:
https://github.com/triaxtec/openapi-python-client/blob/c7da89e201c66caf123961afd76cd5a38b2fec88/openapi_python_client/parser/properties/__init__.py#L629
https://github.com/triaxtec/openapi-python-client/blob/c7da89e201c66caf123961afd76cd5a38b2fec88/openapi_python_client/parser/properties/schemas.py#L121-L126
When an recursive reference is detected, we create a
_Holder
for it and return anRecursiveReferenceInterupt
to the build loophttps://github.com/triaxtec/openapi-python-client/blob/c7da89e201c66caf123961afd76cd5a38b2fec88/openapi_python_client/parser/properties/__init__.py#L633-L642
Tiny trick here, I'm using the error to return the updated version of schema (which contains a reference to an not existing Property class); That not resolved items will be then re-processed at the end of the main build loop:
https://github.com/triaxtec/openapi-python-client/blob/c7da89e201c66caf123961afd76cd5a38b2fec88/openapi_python_client/parser/properties/__init__.py#L649-L653
Now come the part of the ModelProperty construction, during the creation of one of its property from a reference, If the underlaying holded data is an
RecursiveReferenceInterupt
, it will create anLazySelfReferenceProperty
, passing to it the_Holder
object which currently contains anRecursiveReferenceInterupt
but will later on, after its re-processing will contain a validModelProperty
https://github.com/triaxtec/openapi-python-client/blob/c7da89e201c66caf123961afd76cd5a38b2fec88/openapi_python_client/parser/properties/__init__.py#L456-L486
The
LazySelfReferenceProperty
will then proxy the required method call to theModelProperty
contains in the_Holder
object:https://github.com/triaxtec/openapi-python-client/blob/c7da89e201c66caf123961afd76cd5a38b2fec88/openapi_python_client/parser/properties/__init__.py#L37-L87
This PR is not fully ready yet, I haven't updated the unit tests (but the golden records have been updated for the reference), I will wait for feedback regarding the used strategy before moving forward.