Merge pull request #2472 from wing328/python_auto_doc

[Python] automatically generate documentation (markdown) for Python API client
This commit is contained in:
wing328
2016-04-09 18:41:14 +08:00
28 changed files with 2363 additions and 106 deletions

View File

@@ -3,6 +3,7 @@ package io.swagger.codegen.languages;
import io.swagger.codegen.CliOption;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.CodegenConstants;
import io.swagger.codegen.CodegenParameter;
import io.swagger.codegen.CodegenType;
import io.swagger.codegen.DefaultCodegen;
import io.swagger.codegen.SupportingFile;
@@ -17,6 +18,8 @@ import org.apache.commons.lang.StringUtils;
public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig {
protected String packageName;
protected String packageVersion;
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
public PythonClientCodegen() {
super();
@@ -28,6 +31,9 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
apiTemplateFiles.put("api.mustache", ".py");
embeddedTemplateDir = templateDir = "python";
modelDocTemplateFiles.put("model_doc.mustache", ".md");
apiDocTemplateFiles.put("api_doc.mustache", ".md");
languageSpecificPrimitives.clear();
languageSpecificPrimitives.add("int");
languageSpecificPrimitives.add("float");
@@ -36,6 +42,7 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
languageSpecificPrimitives.add("str");
languageSpecificPrimitives.add("datetime");
languageSpecificPrimitives.add("date");
languageSpecificPrimitives.add("object");
typeMapping.clear();
typeMapping.put("integer", "int");
@@ -97,6 +104,10 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);
// make api and model doc path available in mustache template
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
String swaggerFolder = packageName;
modelPackage = swaggerFolder + File.separatorChar + "models";
@@ -138,6 +149,27 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
return "_" + name;
}
@Override
public String apiDocFileFolder() {
return (outputFolder + "/" + apiDocPath);
}
@Override
public String modelDocFileFolder() {
return (outputFolder + "/" + modelDocPath);
}
@Override
public String toModelDocFilename(String name) {
return toModelName(name);
}
@Override
public String toApiDocFilename(String name) {
return toApiName(name);
}
@Override
public String apiFileFolder() {
return outputFolder + File.separatorChar + apiPackage().replace('.', File.separatorChar);
@@ -388,4 +420,70 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
return null;
}
@Override
public void setParameterExampleValue(CodegenParameter p) {
String example;
if (p.defaultValue == null) {
example = p.example;
} else {
example = p.defaultValue;
}
String type = p.baseType;
if (type == null) {
type = p.dataType;
}
if ("String".equalsIgnoreCase(type) || "str".equalsIgnoreCase(type)) {
if (example == null) {
example = p.paramName + "_example";
}
example = "'" + escapeText(example) + "'";
} else if ("Integer".equals(type) || "int".equals(type)) {
if (example == null) {
example = "56";
}
} else if ("Float".equalsIgnoreCase(type) || "Double".equalsIgnoreCase(type)) {
if (example == null) {
example = "3.4";
}
} else if ("BOOLEAN".equalsIgnoreCase(type) || "bool".equalsIgnoreCase(type)) {
if (example == null) {
example = "True";
}
} else if ("file".equalsIgnoreCase(type)) {
if (example == null) {
example = "/path/to/file";
}
example = "'" + escapeText(example) + "'";
} else if ("Date".equalsIgnoreCase(type)) {
if (example == null) {
example = "2013-10-20";
}
example = "'" + escapeText(example) + "'";
} else if ("DateTime".equalsIgnoreCase(type)) {
if (example == null) {
example = "2013-10-20T19:20:30+01:00";
}
example = "'" + escapeText(example) + "'";
} else if (!languageSpecificPrimitives.contains(type)) {
// type is a model class, e.g. User
example = this.packageName + "." + type + "()";
} else {
LOGGER.warn("Type " + type + " not handled properly in setParameterExampleValue");
}
if (example == null) {
example = "NULL";
} else if (Boolean.TRUE.equals(p.isListContainer)) {
example = "[" + example + "]";
} else if (Boolean.TRUE.equals(p.isMapContainer)) {
example = "{'key': " + example + "}";
}
p.example = example;
}
}

View File

@@ -1,73 +1,122 @@
# {{packageName}}
{{#appDescription}}
{{{appDescription}}}
{{/appDescription}}
This Python package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project:
- API version: {{appVersion}}
- Package version: {{packageVersion}}
- Build date: {{generatedDate}}
- Build package: {{generatorClass}}
{{#infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/infoUrl}}
## Requirements.
Python 2.7 and later.
## Setuptools
You can install the bindings via [Setuptools](http://pypi.python.org/pypi/setuptools).
Python 2.7 and 3.4+
## Installation & Usage
### pip install
If the python package is hosted on Github, you can install directly from Github
```sh
python setup.py install
pip install git+https://github.com/{{{gitUserId}}}/{{{gitRepoId}}}.git
```
(you may need to run `pip` with root permission: `sudo pip install git+https://github.com/{{{gitUserId}}}/{{{gitRepoId}}}.git`)
Then import the package:
```python
import {{{packageName}}}
```
Or you can install from Github via pip:
### Setuptools
Install via [Setuptools](http://pypi.python.org/pypi/setuptools).
```sh
pip install git+https://github.com/geekerzp/swagger_client.git
python setup.py install --user
```
(or `sudo python setup.py install` to install the package for all users)
To use the bindings, import the pacakge:
Then import the package:
```python
import swagger_client
```
## Manual Installation
If you do not wish to use setuptools, you can download the latest release.
Then, to use the bindings, import the package:
```python
import path.to.swagger_client
import {{{packageName}}}
```
## Getting Started
TODO
Please follow the [installation procedure](#installation--usage) and then run the following:
## Documentation
```python
import time
import {{{packageName}}}
from {{{packageName}}}.rest import ApiException
from pprint import pprint
{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}}
# Configure HTTP basic authorization: {{{name}}}
{{{packageName}}}.configuration.username = 'YOUR_USERNAME'
{{{packageName}}}.configuration.password = 'YOUR_PASSWORD'{{/isBasic}}{{#isApiKey}}
# Configure API key authorization: {{{name}}}
{{{packageName}}}.configuration.api_key['{{{keyParamName}}}'] = 'YOUR_API_KEY'
# Uncomment below to setup prefix (e.g. BEARER) for API key, if needed
# {{{packageName}}}.configuration.api_key_prefix['{{{keyParamName}}}'] = 'BEARER'{{/isApiKey}}{{#isOAuth}}
# Configure OAuth2 access token for authorization: {{{name}}}
{{{packageName}}}.configuration.access_token = 'YOUR_ACCESS_TOKEN'{{/isOAuth}}{{/authMethods}}
{{/hasAuthMethods}}
# create an instance of the API class
api_instance = {{{packageName}}}.{{{classname}}}
{{#allParams}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}
{{/allParams}}
TODO
## Tests
(Please make sure you have [virtualenv](http://docs.python-guide.org/en/latest/dev/virtualenvs/) installed)
Execute the following command to run the tests in the current Python (v2 or v3) environment:
```sh
$ make test
[... magically installs dependencies and runs tests on your virtualenv]
Ran 7 tests in 19.289s
OK
try:
{{#summary}} # {{{.}}}
{{/summary}} {{#returnType}}api_response = {{/returnType}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}}
pprint(api_response){{/returnType}}
except ApiException as e:
print "Exception when calling {{classname}}->{{operationId}}: %s\n" % e
{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
```
or
```
$ mvn integration-test -rf :PythonPetstoreClientTests
Using 2195432783 as seed
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 37.594 s
[INFO] Finished at: 2015-05-16T18:00:35+08:00
[INFO] Final Memory: 11M/156M
[INFO] ------------------------------------------------------------------------
```
If you want to run the tests in all the python platforms:
## Documentation for API Endpoints
```sh
$ make test-all
[... tox creates a virtualenv for every platform and runs tests inside of each]
py27: commands succeeded
py34: commands succeeded
congratulations :)
```
All URIs are relative to *{{basePath}}*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
## Documentation For Models
{{#models}}{{#model}} - [{{{classname}}}]({{modelDocPath}}{{{classname}}}.md)
{{/model}}{{/models}}
## Documentation For Authorization
{{^authMethods}} All endpoints do not require authorization.
{{/authMethods}}{{#authMethods}}{{#last}} Authentication schemes defined for the API:{{/last}}{{/authMethods}}
{{#authMethods}}## {{{name}}}
{{#isApiKey}}- **Type**: API key
- **API key parameter name**: {{{keyParamName}}}
- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
{{/isApiKey}}
{{#isBasic}}- **Type**: HTTP basic authentication
{{/isBasic}}
{{#isOAuth}}- **Type**: OAuth
- **Flow**: {{{flow}}}
- **Authorizatoin URL**: {{{authorizationUrl}}}
- **Scopes**: {{^scopes}}N/A{{/scopes}}
{{#scopes}} - **{{{scope}}}**: {{{description}}}
{{/scopes}}
{{/isOAuth}}
{{/authMethods}}
## Author
{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}}
{{/hasMore}}{{/apis}}{{/apiInfo}}

View File

@@ -47,7 +47,7 @@ class {{classname}}(object):
self.api_client = config.api_client
{{#operation}}
def {{nickname}}(self, {{#sortParamsByRequiredFlag}}{{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}{{/sortParamsByRequiredFlag}}**kwargs):
def {{operationId}}(self, {{#sortParamsByRequiredFlag}}{{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}{{/sortParamsByRequiredFlag}}**kwargs):
"""
{{{summary}}}
{{{notes}}}
@@ -59,10 +59,10 @@ class {{classname}}(object):
>>> pprint(response)
>>>
{{#sortParamsByRequiredFlag}}
>>> thread = api.{{nickname}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}callback=callback_function)
>>> thread = api.{{operationId}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}callback=callback_function)
{{/sortParamsByRequiredFlag}}
{{^sortParamsByRequiredFlag}}
>>> thread = api.{{nickname}}({{#allParams}}{{#required}}{{paramName}}={{paramName}}_value, {{/required}}{{/allParams}}callback=callback_function)
>>> thread = api.{{operationId}}({{#allParams}}{{#required}}{{paramName}}={{paramName}}_value, {{/required}}{{/allParams}}callback=callback_function)
{{/sortParamsByRequiredFlag}}
:param callback function: The callback function
@@ -83,7 +83,7 @@ class {{classname}}(object):
if key not in all_params:
raise TypeError(
"Got an unexpected keyword argument '%s'"
" to method {{nickname}}" % key
" to method {{operationId}}" % key
)
params[key] = val
del params['kwargs']
@@ -92,7 +92,7 @@ class {{classname}}(object):
{{#required}}
# verify the required parameter '{{paramName}}' is set
if ('{{paramName}}' not in params) or (params['{{paramName}}'] is None):
raise ValueError("Missing the required parameter `{{paramName}}` when calling `{{nickname}}`")
raise ValueError("Missing the required parameter `{{paramName}}` when calling `{{operationId}}`")
{{/required}}
{{/allParams}}

View File

@@ -0,0 +1,74 @@
# {{packageName}}.{{classname}}{{#description}}
{{description}}{{/description}}
All URIs are relative to *{{basePath}}*
Method | HTTP request | Description
------------- | ------------- | -------------
{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}}
{{/operation}}{{/operations}}
{{#operations}}
{{#operation}}
# **{{{operationId}}}**
> {{#returnType}}{{{returnType}}} {{/returnType}}{{{operationId}}}({{#allParams}}{{#required}}{{{paramName}}}{{/required}}{{^required}}{{{paramName}}}={{{paramName}}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
{{{summary}}}{{#notes}}
{{{notes}}}{{/notes}}
### Example
```python
import time
import {{{packageName}}}
from {{{packageName}}}.rest import ApiException
from pprint import pprint
{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}}
# Configure HTTP basic authorization: {{{name}}}
{{{packageName}}}.configuration.username = 'YOUR_USERNAME'
{{{packageName}}}.configuration.password = 'YOUR_PASSWORD'{{/isBasic}}{{#isApiKey}}
# Configure API key authorization: {{{name}}}
{{{packageName}}}.configuration.api_key['{{{keyParamName}}}'] = 'YOUR_API_KEY'
# Uncomment below to setup prefix (e.g. BEARER) for API key, if needed
# {{{packageName}}}.configuration.api_key_prefix['{{{keyParamName}}}'] = 'BEARER'{{/isApiKey}}{{#isOAuth}}
# Configure OAuth2 access token for authorization: {{{name}}}
{{{packageName}}}.configuration.access_token = 'YOUR_ACCESS_TOKEN'{{/isOAuth}}{{/authMethods}}
{{/hasAuthMethods}}
# create an instance of the API class
api_instance = {{{packageName}}}.{{{classname}}}()
{{#allParams}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}
{{/allParams}}
try:
{{#summary}} # {{{.}}}
{{/summary}} {{#returnType}}api_response = {{/returnType}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}}
pprint(api_response){{/returnType}}
except ApiException as e:
print "Exception when calling {{classname}}->{{operationId}}: %s\n" % e
```
### Parameters
{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}}
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}}
{{#allParams}} **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}}
{{/allParams}}
### Return type
{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void (empty response body){{/returnType}}
### Authorization
{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../README.md#{{{name}}}){{^-last}}, {{/-last}}{{/authMethods}}
### HTTP reuqest headers
- **Content-Type**: {{#consumes}}{{mediaType}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}}
- **Accept**: {{#produces}}{{mediaType}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}}
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
{{/operation}}
{{/operations}}

View File

@@ -0,0 +1,11 @@
{{#models}}{{#model}}# {{classname}}
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
{{#vars}}**{{name}}** | {{#isPrimitiveType}}**{{datatype}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{datatype}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}}
{{/vars}}
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
{{/model}}{{/models}}