Skip to content

Commit

Permalink
feat: use openapi codegen for py client
Browse files Browse the repository at this point in the history
  • Loading branch information
lyuyangh committed May 10, 2022
1 parent da212e2 commit f864d25
Show file tree
Hide file tree
Showing 55 changed files with 7,191 additions and 9 deletions.
17 changes: 9 additions & 8 deletions .github/workflows/py-client-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: "Python API Client Release"

on:
push:
branches: [main]
paths: ["openapi/openapi.yaml"]
branches: [main, "feat/openapi-py-client"]
paths: ["openapi/openapi.yaml", ".github/workflows/py-client-release.yml"]

jobs:
build-and-release:
Expand All @@ -16,23 +16,24 @@ jobs:
uses: actions/setup-python@v1
with:
python-version: 3.9

- name: "generate tag from SHA"
id: gen_tag
run: echo "::set-output name=tag::$(echo ${GITHUB_SHA} | cut -c1-7)"

- name: Install dependencies
run: |
apt-get update && apt-get install -y default-jre
pip install wheel
- name: Generate Python Client
run: |
wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.29/swagger-codegen-cli-3.0.29.jar -O swagger-codegen-cli-3.0.29.jar
java -jar swagger-codegen-cli-3.0.29.jar generate -i openapi/openapi.yaml -l python -o python_client -DpackageName=explainaboard_api_client
wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/5.4.0/openapi-generator-cli-5.4.0.jar -O openapi-generator-cli.jar
java -jar openapi-generator-cli.jar generate -i openapi/openapi.yaml -g python-experimental -o python_client -t openapi/python_explerimental_client_template "--additional-properties=packageName=explainaboard_api_client,packageVersion=${{ steps.gen_tag.outputs.tag }}"
- name: "build"
run: |
cd python_client
python setup.py bdist_wheel
- name: "generate tag from SHA"
id: gen_tag
run: echo "::set-output name=tag::$(echo ${GITHUB_SHA} | cut -c1-7)"

- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ __pycache__
# swagger codegen
backend/src/gen
swagger-codegen-cli*.jar
openapi-generator-cli*.jar
frontend/src/clients/openapi

openapi/python_client
.env
57 changes: 57 additions & 0 deletions openapi/python_explerimental_client_template/README.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# {{{projectName}}}
{{#if appDescriptionWithNewLines}}
{{{appDescriptionWithNewLines}}}
{{/if}}

This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:

- API version: {{appVersion}}
- Package version: {{packageVersion}}
{{#unless hideGenerationTimestamp}}
- Build date: {{generatedDate}}
{{/unless}}
- Build package: {{generatorClass}}
{{#if infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/if}}

## Requirements.

Python {{generatorLanguageVersion}}
v3.9 is needed so one can combine classmethod and property decorators to define
object schema properties as classes

## Installation & Usage
### pip install

If the python package is hosted on a repository, you can install directly using:

```sh
pip install git+https://{{gitHost}}/{{{gitUserId}}}/{{{gitRepoId}}}.git
```
(you may need to run `pip` with root permission: `sudo pip install git+https://{{gitHost}}/{{{gitUserId}}}/{{{gitRepoId}}}.git`)

Then import the package:
```python
import {{{packageName}}}
```

### Setuptools

Install via [Setuptools](http://pypi.python.org/pypi/setuptools).

```sh
python setup.py install --user
```
(or `sudo python setup.py install` to install the package for all users)

Then import the package:
```python
import {{{packageName}}}
```

## Getting Started

Please follow the [installation procedure](#installation--usage) and then run the following:

{{> README_common }}
111 changes: 111 additions & 0 deletions openapi/python_explerimental_client_template/README_common.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
```python
{{#with apiInfo}}{{#each apis}}{{#unless hasMore}}{{#if hasHttpSignatureMethods}}import datetime{{/if}}{{/unless}}{{/each}}{{/with}}
import time
import {{{packageName}}}
from pprint import pprint
{{#with apiInfo}}
{{#each apis}}
{{#if @first}}
from {{packageName}}.{{apiPackage}} import {{classFilename}}
{{#each imports}}
{{{import}}}
{{/each}}
{{#with operations}}
{{#each operation}}
{{#if @first}}
{{> doc_auth_partial}}

# Enter a context with an instance of the API client
with {{{packageName}}}.ApiClient(configuration) as api_client:
# Create an instance of the API class
api_instance = {{classFilename}}.{{{classname}}}(api_client)
{{#each allParams}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{#unless required}} (optional){{/unless}}{{#if defaultValue}} (default to {{{.}}}){{/if}}
{{/each}}

try:
{{#if summary}} # {{{summary}}}
{{/if}} {{#if returnType}}api_response = {{/if}}api_instance.{{{operationId}}}({{#each allParams}}{{#if required}}{{paramName}}{{/if}}{{#unless required}}{{paramName}}={{paramName}}{{/unless}}{{#if hasMore}}, {{/if}}{{/each}}){{#if returnType}}
pprint(api_response){{/if}}
except {{{packageName}}}.ApiException as e:
print("Exception when calling {{classname}}->{{operationId}}: %s\n" % e)
{{/if}}
{{/each}}
{{/with}}
{{/if}}
{{/each}}
{{/with}}
```

## Documentation for API Endpoints

All URIs are relative to *{{basePath}}*

Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
{{#with apiInfo}}{{#each apis}}{{#with operations}}{{#each operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#if summary}}{{summary}}{{/if}}
{{/each}}{{/with}}{{/each}}{{/with}}
## Documentation For Models
{{#each models}}{{#with model}} - [{{{classname}}}]({{modelDocPath}}{{{classname}}}.md)
{{/with}}{{/each}}
## Documentation For Authorization
{{#unless authMethods}}
All endpoints do not require authorization.
{{/unless}}
{{#each authMethods}}
{{#if @last}} Authentication schemes defined for the API:{{/if}}
## {{{name}}}
{{#if isApiKey}}
- **Type**: API key
- **API key parameter name**: {{{keyParamName}}}
- **Location**: {{#if isKeyInQuery}}URL query string{{/if}}{{#if isKeyInHeader}}HTTP header{{/if}}
{{/if}}
{{#if isBasic}}
{{#if isBasicBasic}}
- **Type**: HTTP basic authentication
{{/if}}
{{#if isBasicBearer}}
- **Type**: Bearer authentication{{#if bearerFormat}} ({{{bearerFormat}}}){{/if}}
{{/if}}
{{#if isHttpSignature}}
- **Type**: HTTP signature authentication
{{/if}}
{{/if}}
{{#if isOAuth}}
- **Type**: OAuth
- **Flow**: {{{flow}}}
- **Authorization URL**: {{{authorizationUrl}}}
- **Scopes**: {{#unless scopes}}N/A{{/unless}}
{{#each scopes}} - **{{{scope}}}**: {{{description}}}
{{/each}}
{{/if}}
{{/each}}
## Author
{{#with apiInfo}}{{#each apis}}{{#unless hasMore}}{{infoEmail}}
{{/unless}}{{/each}}{{/with}}
## Notes for Large OpenAPI documents
If the OpenAPI document is large, imports in {{{packageName}}}.apis and {{{packageName}}}.models may fail with a
RecursionError indicating the maximum recursion limit has been exceeded. In that case, there are a couple of solutions:
Solution 1:
Use specific imports for apis and models like:
- `from {{{packageName}}}.{{apiPackage}}.default_api import DefaultApi`
- `from {{{packageName}}}.{{modelPackage}}.pet import Pet`
Solution 1:
Before importing the package, adjust the maximum recursion limit as shown below:
```
import sys
sys.setrecursionlimit(1500)
import {{{packageName}}}
from {{{packageName}}}.apis import *
from {{{packageName}}}.models import *
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# {{{projectName}}}
{{#if appDescription}}
{{{appDescription}}}
{{/if}}

The `{{packageName}}` package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:

- API version: {{appVersion}}
- Package version: {{packageVersion}}
{{#unless hideGenerationTimestamp}}
- Build date: {{generatedDate}}
{{/unless}}
- Build package: {{generatorClass}}
{{#if infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/if}}

## Requirements.

Python {{generatorLanguageVersion}}

## Installation & Usage

This python library package is generated without supporting files like setup.py or requirements files

To be able to use it, you will need these dependencies in your own package that uses this library:

* urllib3 >= 1.15
* certifi
* python-dateutil
{{#if asyncio}}
* aiohttp
{{/if}}
{{#if tornado}}
* tornado>=4.2,<5
{{/if}}

## Getting Started

In your own code, to use this library to connect and interact with {{{projectName}}},
you can run the following:

{{> README_common }}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{#with apiInfo}}
{{#each apis}}
{{#if @first}}
# do not import all apis into this module because that uses a lot of memory and stack frames
# if you need the ability to import all apis from one package, import them with
# from {{packageName}}.apis import {{classname}}
{{/if}}
{{/each}}
{{/with}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{#with apiInfo}}
{{#each apis}}
{{#if @first}}
# coding: utf-8

# flake8: noqa

# Import all APIs into this package.
# If you have many APIs here with many many models used in each API this may
# raise a `RecursionError`.
# In order to avoid this, import only the API that you directly need like:
#
# from {{packagename}}.{{apiPackage}}.{{classFilename}} import {{classname}}
#
# or import this package, but before doing it, use:
#
# import sys
# sys.setrecursionlimit(n)

# Import APIs into API package:
{{/if}}
from {{packageName}}.{{apiPackage}}.{{classFilename}} import {{classname}}
{{/each}}
{{/with}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# we can not import model classes here because that would create a circular
# reference which would not work in python2
# do not import all models into this module because that uses a lot of memory and stack frames
# if you need the ability to import all models from one package, import them with
# from {{packageName}}.models import ModelA, ModelB
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# coding: utf-8

# flake8: noqa

# import all models into this package
# if you have many models here with many references from one model to another this may
# raise a RecursionError
# to avoid this, import only the models that you directly need like:
# from from {{packageName}}.{{modelPackage}}.pet import Pet
# or import this package, but before doing it, use:
# import sys
# sys.setrecursionlimit(n)

{{#each models}}
{{#with model}}
from {{packageName}}.{{modelPackage}}.{{classFilename}} import {{classname}}
{{/with}}
{{/each}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# coding: utf-8

# flake8: noqa

{{>partial_header}}

__version__ = "{{packageVersion}}"

# import ApiClient
from {{packageName}}.api_client import ApiClient

# import Configuration
from {{packageName}}.configuration import Configuration
{{#if hasHttpSignatureMethods}}
from {{packageName}}.signing import HttpSigningConfiguration
{{/if}}

# import exceptions
from {{packageName}}.exceptions import OpenApiException
from {{packageName}}.exceptions import ApiAttributeError
from {{packageName}}.exceptions import ApiTypeError
from {{packageName}}.exceptions import ApiValueError
from {{packageName}}.exceptions import ApiKeyError
from {{packageName}}.exceptions import ApiException
{{#if recursionLimit}}

__import__('sys').setrecursionlimit({{recursionLimit}})
{{/if}}
26 changes: 26 additions & 0 deletions openapi/python_explerimental_client_template/api.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# coding: utf-8

{{>partial_header}}

from {{packageName}}.api_client import ApiClient
{{#with operations}}
{{#each operation}}
from {{packageName}}.api.{{classFilename}}_endpoints.{{operationId}} import {{operationIdCamelCase}}
{{/each}}
{{/with}}


{{#with operations}}
class {{classname}}(
{{#each operation}}
{{operationIdCamelCase}},
{{/each}}
ApiClient,
):
"""NOTE: This class is auto generated by OpenAPI Generator
Ref: https://openapi-generator.tech

Do not edit the class manually.
"""
pass
{{/with}}
Loading

0 comments on commit f864d25

Please sign in to comment.