-
-
Notifications
You must be signed in to change notification settings - Fork 227
feat: templatize api, endpoint init files #403
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
feat: templatize api, endpoint init files #403
Conversation
4093e72
to
e0e8302
Compare
Codecov Report
@@ Coverage Diff @@
## main #403 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 47 47
Lines 1558 1563 +5
=========================================
+ Hits 1558 1563 +5
Continue to review full report at Codecov.
|
openapi_python_client/__init__.py
Outdated
package_name=self.package_name, | ||
endpoint_collections_by_tag=endpoint_collections_by_tag, |
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 assume you're passing these params because you need them, but for a developer working on just openapi-python-client
it looks like these are not needed and might get removed at some point. I suggest either adding a note here or, better yet, a custom template in the end to end tests which uses them so we can see why they're there.
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.
Good catch. I followed your recommendation:
-
eda38ed Add new custom template tests, I had to change a little bit how the expected diff was handled:
- Instead of a dict of {filename: content} it now use a dict of {file path: content}, to be able to handle files that have the same name but are defined at different paths
- Since I've added a custom template sample, directly hardcoding the expected content seems to become a bad idea. That's why I propose to introduce the
custom-templates-golden-record
which contains all expected diff when using custom templates
96fcdd6 add the
custom-templates-golden-record
generation to theregen
task
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.
We used to generate a complete golden-record for custom to compare as well but code reviews got really burdensome since the same content would effectively change twice and it didn't add much value. At a glance, it looks like you've set it up to only generate the specific files we're interested in so that should be a good middleground between the two approaches (generate everything vs generate nothing). I'll take a deeper look later on, thanks!
b7de1ed
to
96fcdd6
Compare
{%- for part in name -%} | ||
{{ '_' if not loop.first and part in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' and (loop.index - last_snakize.at) > 1 and not last_snakize.update({'at': loop.index}) }}{{ part | lower }} | ||
{%- endfor -%} | ||
{% endmacro %} |
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.
this macro will render wrong names module__enpoint_func
with extra underscore.
@dbanty whouldn't it be nice to expose utils methods to jinja templates?
by just adding to Project class
self.env.globals.update(snake_case=snake_case, pascal_case=pascal_case)
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.
Probably? I don't use custom templates at all and they aren't considered stable, I just mostly approve other folks' contributions for now so they can do what they need. If having those available in custom templates would be useful to you then we can totally pass them through. I think in the primary templates though we don't do any string transformations, it's all done in the Python parsing code.
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 agree, it will be nice to have, best I thinks will be to make https://github.com/triaxtec/openapi-python-client/blob/main/openapi_python_client/utils.py accessible to jinja.
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.
9a5cf23
to
2715dbf
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.
@p1-ra very good job!
Please take a look at #431, (my bad 😅, I did not notice this PR and tried to implement same thing) maybe some test ideas could be useful, like this one:
dircmp
already does cmpfiles
internally and stores the same result in diff_files
and funny_files
. Reference: https://github.com/python/cpython/blob/main/Lib/filecmp.py#L186
So it just need some parsing to retrieve the result recursively from the subdirectories.
openapi_python_client/__init__.py
Outdated
endpoint_init_path = tag_dir / "__init__.py" | ||
endpoint_init_template = self.env.get_template("endpoint_init.py.jinja") | ||
endpoint_init_path.write_text( | ||
endpoint_init_template.render(package_name=self.package_name, tag=tag, endpoints=collection.endpoints), |
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.
EndpointCollection
does already have a tag
attribute so it would be cleaner to pass the object:
endpoint_init_template.render(package_name=self.package_name, tag=tag, endpoints=collection.endpoints), | |
endpoint_init_template.render(package_name=self.package_name, endpoint_collection=collection), |
And about the package_name
, probably not really needed as a relative import always can be done. If we do pass it, maybe we would also need to pass it also to endpoint_module.py.jinja
template also for consistency (Note that I am not against passing it, just a thought) (Edit: nevermind, I see in the examples that you use it for other purposes in addition to imports, like for generating a class name)
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.
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.
Please review other template rendering in this file where package_name
is passed.
Also I see some renders with description
and version
instead of package_description
and package_version
so that could be unified.
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.
Indeed, normalized on d1120f2
I've also wildly spread the project metadata vars to all template
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.
@dbanty what do you thinks about it? We are including a breaking change here by renaming {version, description}
to {package_version, package_description}
.
Imo, package_X
kind of make more sense if we spread them accross all templates
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 template API is not stable, so I don't care too much about breaking changes to it 😅. So I'm good with adding some clarity / consistency.
api_init_path.write_text( | ||
api_init_template.render( | ||
package_name=self.package_name, | ||
endpoint_collections_by_tag=endpoint_collections_by_tag, |
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 would suggest passing endpoint_collections_by_tag
in the dictionary form instead of a list (after doing .items()
) for two reasons:
- Naming may be confusing as
self.openapi.endpoint_collections_by_tag
is dictionary but in the templateendpoint_collections_by_tag
is a list. - It is more flexible and allows easily looping on unique tags
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.
Agreed, resolved in cdd304c
end_to_end_tests/test_end_to_end.py
Outdated
@@ -12,7 +12,10 @@ | |||
def _compare_directories( | |||
record: Path, | |||
test_subject: Path, | |||
expected_differences: Optional[Dict[str, str]] = None, | |||
expected_differences: Optional[ | |||
Dict[str, str] |
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 this should be Optional[Dict[Path,str]]
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.
Indeed, resolved in b541e01
77acd25
to
d1120f2
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.
Awesome, great work! Glad to see so much thought being put into the templates by the community 💜. I have a couple suggestions, mostly around making the e2e tests a bit cleaner (IMO). I tested locally and my changes all passed, but I could have messed something up pasting into GitHub so let me know if you have any issues (or fundamentally disagree with the changes). Thank you!!
…which will cause some to be renamed [openapi-generators#413][openapi-generators#432]. Thanks @ramnes!
…r complex types (openapi-generators#372). Thanks @csymeonides-mf! * fix: Detect File fields correctly * fix: Optional File field caused missing import error * fix: Non-string multipart fields must be stringified * chore: Reformat * fix: Put non-file fields as tuples in the files dict * refactor: Avoid runtime type checks * fix: Declaring types is necessary * fix: Remove dead code * fix: Non-JSON non-file multipart props need to be text/plain * refactor: Avoid breaking change Co-authored-by: Constantinos Symeonides <[email protected]>
… imprv Co-authored-by: Dylan Anthony <[email protected]>
d3ee968
to
ae18d84
Compare
I've merged your suggestions and rebased on top of current main branch @dbanty |
This PR add the api and endpoint
init.py
file as template. I had specifics needs for it, may be useful for others.BR.