-
-
Notifications
You must be signed in to change notification settings - Fork 5
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 pre loaded AsyncAPISpec in from_spec #160
Allow pre loaded AsyncAPISpec in from_spec #160
Conversation
Codecov Report
@@ Coverage Diff @@
## main #160 +/- ##
==========================================
+ Coverage 97.09% 97.11% +0.01%
==========================================
Files 11 11
Lines 895 900 +5
==========================================
+ Hits 869 874 +5
Misses 26 26
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
asynction/server.py
Outdated
@@ -113,7 +114,7 @@ def init_app(self, app: Optional[Flask], **kwargs) -> None: | |||
@classmethod | |||
def from_spec( | |||
cls, | |||
spec_path: Path, | |||
spec: Union[Path, AsyncApiSpec], |
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.
spec: Union[Path, AsyncApiSpec], | |
spec_path: Union[Path, JSONMapping], |
2 points to discuss here:
- I would be keen to avoid exposing the
AsyncApiSpec
type as part of Asynction's public API. This will restrict us from being able to make backwards incompatible changes to the class, unless we bump the major version of the whole package. Besides the type, we will also have to expose theload_spec
method (the type alone is pretty useless), which I would also like to avoid for the same reason. Instead of passing the typed object, we could have users passing the raw dict of their AsyncAPI spec. Hence, we would have thefrom_spec
factory method supporting file paths as well as raw dict data. The latter will account for use cases such as deep merging multiple spec files into one dict (the use case of yours) or converting class definitions to JSONSchemata. When it comes to the merging of multiple files, there is the shortcoming that without the type and the loader function users won't be able to ensure that each of the spec files has a valid and complete AsyncAPI data structure. However I would argue that this is not the responsibility of Asynction. This would be the responsibility of a parser library like asyncapi/parser-js. Unfortunately, python does not have such a library yet, but I'm currently working on one that I expect to release towards the end of Jan. - Renaming the argument name from
spec_path
tospec
is a backwards incompatible change to Asynction's public API, which will require a major version bump. Of coursespec_path
is not an accurate name anymore, but I would like to introduce this change only when Asynction is ready for the 1.0.0 bump. I will create an issue where we can collect all the items that we need to modify ahead of the 1.0.0 stable release.
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.
When it comes to the merging of multiple files, there is the shortcoming that without the type and the loader function users won't be able to ensure that each of the spec files has a valid and complete AsyncAPI data structure. However I would argue that this is not the responsibility of Asynction.
@alex-zywicki For the time being, If there is a requirement on your end to ensure that each file has a complete and valid AsyncAPI structure, you can use the existing methods of Asynction, but with the risk of having to modify parts of your code when you upgrade to a new minor version of the package.
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.
@dedoussis It is not an issue on my end to have to modify my code if something in the types.py
changes. I have my asynction
version pinned to nothing will break unless I explicitly choose to upgrade the version. I will amend the pr to undo the name changes.
bcb7170
to
daf3cf0
Compare
asynction/server.py
Outdated
@@ -113,7 +114,7 @@ def init_app(self, app: Optional[Flask], **kwargs) -> None: | |||
@classmethod | |||
def from_spec( | |||
cls, | |||
spec_path: Path, | |||
spec_path: Union[Path, AsyncApiSpec], |
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.
spec_path: Union[Path, AsyncApiSpec], | |
spec_path: Union[Path, JSONMapping], |
See the previous comment I made with regards to exposing the AsyncApiSpec
type.
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.
@dedoussis Are you saying to just change the type annotations? how would the implementation change? Would I still be able to pass an AsyncApiSpec
or what would I pass?
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.
@alex-zywicki This would also be an implementation change.
I propose the from_spec
method to accept either a file path or a dict. In the case of dict, the conversion of the given dictionary into an AsyncApiSpec
object should happen internally within Asynction. This way we can avoid exposing the type to the user. See point 1 of my comment above:
Instead of passing the typed object, we could have users passing the raw dict of their AsyncAPI spec. Hence, we would have the from_spec factory method supporting file paths as well as raw dict data. The latter will account for use cases such as deep merging multiple spec files into one dict (the use case of yours) or converting class definitions to JSONSchemata.
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.
@dedoussis I guess I'm confused about what you meant when you said a while back
@alex-zywicki For the time being, If there is a requirement on your end to ensure that each file has a complete and valid AsyncAPI structure, you can use the existing methods of Asynction, but with the risk of having to modify parts of your code when you upgrade to a new minor version of the package.
632d203
to
cacffc9
Compare
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.
Looks sensible, thank you! Couple of minor comments.
asynction/server.py
Outdated
:param spec_path: The path where the AsyncAPI YAML specification is located, | ||
or a pre loaded JSONMapping object. |
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.
:param spec_path: The path where the AsyncAPI YAML specification is located, | |
or a pre loaded JSONMapping object. | |
:param spec_path: The path where the AsyncAPI YAML specification is located, | |
or a dictionary object of the AsyncAPI data structure. |
asynction/server.py
Outdated
if isinstance(spec_path, Path): | ||
spec = load_spec(spec_path=spec_path) | ||
else: | ||
raw_resolved = resolve_references(raw_spec=spec_path) | ||
spec = AsyncApiSpec.from_dict(raw_resolved) |
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.
I think it would be neater if we could move this logic within the existing load_spec
function:
def load_spec(raw_spec: Union[Path, JSONMapping]) -> AsyncApiSpec:
if isinstance(spec, Path):
with open(spec_path) as f:
serialized = f.read()
raw_spec = yaml.safe_load(serialized)
raw_resolved = resolve_references(raw_spec)
return AsyncApiSpec.from_dict(raw_resolved)
Note that here, in the load_spec
method, we can change the argument name from spec_path
to raw_spec
since load_spec
is not part of Asynction's "public" API.
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 above line in the from_spec
method would then become:
if isinstance(spec_path, Path): | |
spec = load_spec(spec_path=spec_path) | |
else: | |
raw_resolved = resolve_references(raw_spec=spec_path) | |
spec = AsyncApiSpec.from_dict(raw_resolved) | |
spec = load_spec(raw_spec=spec_path) |
9857449
to
97be712
Compare
97be712
to
db740c8
Compare
Allow
from_spec
to accept anAsyncApiSpec
object or thePath
to an asyncapi file.This will aid in the implementation of spec merging from #108 by allowing the programmer to load and merge specs and then pass in the merged spec rather than having to write the merged spec back out to file.