-
Notifications
You must be signed in to change notification settings - Fork 13
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
Allow deferring reference resolution to support mutually referencing bundles #82
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## main #82 +/- ##
==========================================
+ Coverage 92.73% 92.80% +0.07%
==========================================
Files 23 23
Lines 2052 2072 +20
Branches 435 440 +5
==========================================
+ Hits 1903 1923 +20
Misses 97 97
Partials 52 52
☔ View full report in Codecov by Sentry. |
Notably, making |
Looking this over for the first time in several months, with the benefit of working on Currently I've essentially re-implemented this outside of the catalog, without having realized that that's what I was doing. There is also added complexity (that isn't and shouldn't be addressed in this PR) that the "metaschema" for OpenAPI documents is different depending on the context of the reference. I'll go deeper into that in a thread in #108 soon-ish. But while I'm very much open to suggestion for anything better, this approach has held up well. |
This adds a constructor option to defer reference resolution until a later call to the now-public method resolve_references()
Constructor and create_catalog parameter gets passed through to all JSONSchema constructor calls. It defaults to True, preserving backwards compatiblity. The resolve_references() method calls resolve_references() on all schemas in the given cache.
EDIT: As a complement or alternative to this PR, PRs #83 and #85 provide near-parity with the status quo for complex mutual references including bundles — this PR adds the ability to handle sets of schemas where:
"$id"
contents are not known in advance, preventing configuration of aSource
to retrieve themThe sources added in PR #85 can be complex to configure, so despite this PR's own complexity, it offers an easier way to manage certain scenarios.
In particular, it enables building generic schema-oriented tools that will have to work with arbitrary sets of schemas provided by whatever code calls the tools (this is the use case that is of particular interest to me, as someone who mostly works on generic tools).
Original comment for this PR:'
Fixes #76, preserving backwards compatibility and the guarantee that schemas will not encounter a reference resolution error when evaluated.
resolve_references
parameter toJSONSchema.__init__()
,Catalog.__init__()
, andcreate_catalog
(), with the latter two passing through the value to the former whenever relevant. All default toTrue
, preserving the current behaviorJSONSchema.references_resolved
data member to track the resolution stateJSONSchema._resolve_references()
to a public methodJSONSchema.resolve_references, which checks
self.references_resolved` to avoid a very expensive no-op if called twiceCatalog.resolve_references()
to resolve all references within a cache, including resolving references to schemas added to the cache during reference resolution, iterating until all are resolved; it takes an optionalcacheid
parameter with the usual defaulting behaviorself.references_resolved
inJSONSchema.evaluate()
and raise aJSONSchemaError
if references have not been resolvedFor more details on usage, see the added tutorial page. This PR contains three commits:
JSONSchema
behavior, except for the change toevaluate()
— this is the fundamental approach, and is sufficient for technical compliance. However, it is not very convenient in many waysCatalog
behavior, allowing dynamic loading to use this behavior, and allowing a schema cache-level resolution to bring a cache into alignment with how it would be if the normal reference resolution had taken place — this provides all the tools necessary to replicate the current experience as a two-step rather than one-step processJSONSchemaError
ifevaluate()
is called with unresolved referencesIt would be trivial to replace commit 3 with a call to the catalog's schema cache-level
resolve_references()
, and I have that available and tested if that behavior would be preferred. It would mean thatevaluate()
could raise aCatalogError
on the first invocation, which seemed like a bigger change. Plus the firstevaluate()
would be much slower. So I went with this more explicit approach.At one point, in the 2nd commit I had the catalog tracking which schemas were and were not resolved, but this introduced substantial complexity to the code so I dropped it. I can post it as an alternative if desired. I suspect the performance was worse, except possibly in the case where a very large schema cache has a very small number of unresolved schemas, in which case the PR as written will spend extra time needlessly calling
resolve_references()
on a lot of schemas. But this is probably rare.At an earlier point, I tried to make a call to
JSONSchema.resolve_references()
cascade through its keywords to resolve any schemas that it referenced, etc. This was even more complicated (and required #78, which this current PR does not), so I dropped it. Again, I can post it as an alternative if desired.As it stands, this PR is the most minimal way I could think of to satisfy the specification requirements regarding bundled schemas.