Skip to content

Commit 84ef98f

Browse files
Matthieu Berthoméwing328
authored andcommitted
[Python][Client] pure library client package (#470)
* Python client pure library package * check onlyPackage CLI option * run /bin/python-petstore.sh, update the python samples for CI * onlyPackage local variable instead of classp property * fix CI: __future__ absolute_import must be first in file * update samples * generateSourceCodeOnly * updated samples
1 parent 925ae68 commit 84ef98f

21 files changed

Lines changed: 223 additions & 140 deletions

File tree

bin/windows/typescript-node-petstore-with-npm.bat

100644100755
File mode changed.

bin/windows/typescript-node-petstore.bat

100644100755
File mode changed.

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ public static enum ENUM_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case,
213213
public static final String EXCLUDE_TESTS = "excludeTests";
214214
public static final String EXCLUDE_TESTS_DESC = "Specifies that no tests are to be generated.";
215215

216+
public static final String SOURCECODEONLY_GENERATION = "generateSourceCodeOnly";
217+
public static final String SOURCECODEONLY_GENERATION_DESC = "Specifies that only a library source code is to be generated.";
218+
216219
// Not user-configurable. System provided for use in templates.
217220

218221
public static final String GENERATE_APIS = "generateApis";

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ public PythonClientCodegen() {
159159
CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG_DESC).defaultValue(Boolean.TRUE.toString()));
160160
cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC)
161161
.defaultValue(Boolean.TRUE.toString()));
162+
cliOptions.add(new CliOption(CodegenConstants.SOURCECODEONLY_GENERATION, CodegenConstants.SOURCECODEONLY_GENERATION_DESC)
163+
.defaultValue(Boolean.FALSE.toString()));
162164

163165
supportedLibraries.put("urllib3", "urllib3-based client");
164166
supportedLibraries.put("asyncio", "Asyncio-based client (python 3.5+)");
@@ -198,10 +200,22 @@ public void processOpts() {
198200
setPackageVersion("1.0.0");
199201
}
200202

203+
Boolean generateSourceCodeOnly = false;
204+
if (additionalProperties.containsKey(CodegenConstants.SOURCECODEONLY_GENERATION)) {
205+
generateSourceCodeOnly = true;
206+
}
207+
201208
additionalProperties.put(CodegenConstants.PROJECT_NAME, projectName);
202209
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
203210
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);
204211

212+
if (generateSourceCodeOnly) {
213+
// tests in <package>/test
214+
testFolder = packageName + File.separatorChar + testFolder;
215+
// api/model docs in <package>/docs
216+
apiDocPath = packageName + File.separatorChar + apiDocPath;
217+
modelDocPath = packageName + File.separatorChar + modelDocPath;
218+
}
205219
// make api and model doc path available in mustache template
206220
additionalProperties.put("apiDocPath", apiDocPath);
207221
additionalProperties.put("modelDocPath", modelDocPath);
@@ -210,12 +224,24 @@ public void processOpts() {
210224
setPackageUrl((String) additionalProperties.get(PACKAGE_URL));
211225
}
212226

213-
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
227+
String readmePath ="README.md";
228+
String readmeTemplate = "README.mustache";
229+
if (generateSourceCodeOnly) {
230+
readmePath = packageName + "_" + readmePath;
231+
readmeTemplate = "README_onlypackage.mustache";
232+
}
233+
supportingFiles.add(new SupportingFile(readmeTemplate, "", readmePath));
214234

215-
supportingFiles.add(new SupportingFile("tox.mustache", "", "tox.ini"));
216-
supportingFiles.add(new SupportingFile("test-requirements.mustache", "", "test-requirements.txt"));
217-
supportingFiles.add(new SupportingFile("requirements.mustache", "", "requirements.txt"));
235+
if (!generateSourceCodeOnly){
236+
supportingFiles.add(new SupportingFile("tox.mustache", "", "tox.ini"));
237+
supportingFiles.add(new SupportingFile("test-requirements.mustache", "", "test-requirements.txt"));
238+
supportingFiles.add(new SupportingFile("requirements.mustache", "", "requirements.txt"));
218239

240+
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
241+
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
242+
supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml"));
243+
supportingFiles.add(new SupportingFile("setup.mustache", "", "setup.py"));
244+
}
219245
supportingFiles.add(new SupportingFile("configuration.mustache", packageName, "configuration.py"));
220246
supportingFiles.add(new SupportingFile("__init__package.mustache", packageName, "__init__.py"));
221247
supportingFiles.add(new SupportingFile("__init__model.mustache", packageName + File.separatorChar + modelPackage, "__init__.py"));
@@ -224,10 +250,7 @@ public void processOpts() {
224250
if (Boolean.FALSE.equals(excludeTests)) {
225251
supportingFiles.add(new SupportingFile("__init__test.mustache", testFolder, "__init__.py"));
226252
}
227-
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
228-
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
229-
supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml"));
230-
supportingFiles.add(new SupportingFile("setup.mustache", "", "setup.py"));
253+
231254
supportingFiles.add(new SupportingFile("api_client.mustache", packageName, "api_client.py"));
232255

233256
if ("asyncio".equals(getLibrary())) {

modules/openapi-generator/src/main/resources/python/README.mustache

Lines changed: 1 addition & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -52,78 +52,4 @@ import {{{packageName}}}
5252

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

55-
```python
56-
from __future__ import print_function
57-
import time
58-
import {{{packageName}}}
59-
from {{{packageName}}}.rest import ApiException
60-
from pprint import pprint
61-
{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}}
62-
# Configure HTTP basic authorization: {{{name}}}
63-
configuration = {{{packageName}}}.Configuration()
64-
configuration.username = 'YOUR_USERNAME'
65-
configuration.password = 'YOUR_PASSWORD'{{/isBasic}}{{#isApiKey}}
66-
# Configure API key authorization: {{{name}}}
67-
configuration = {{{packageName}}}.Configuration()
68-
configuration.api_key['{{{keyParamName}}}'] = 'YOUR_API_KEY'
69-
# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
70-
# configuration.api_key_prefix['{{{keyParamName}}}'] = 'Bearer'{{/isApiKey}}{{#isOAuth}}
71-
# Configure OAuth2 access token for authorization: {{{name}}}
72-
configuration = {{{packageName}}}.Configuration()
73-
configuration.access_token = 'YOUR_ACCESS_TOKEN'{{/isOAuth}}{{/authMethods}}
74-
{{/hasAuthMethods}}
75-
76-
# create an instance of the API class
77-
api_instance = {{{packageName}}}.{{{classname}}}({{{packageName}}}.ApiClient(configuration))
78-
{{#allParams}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}
79-
{{/allParams}}
80-
81-
try:
82-
{{#summary}} # {{{.}}}
83-
{{/summary}} {{#returnType}}api_response = {{/returnType}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}}
84-
pprint(api_response){{/returnType}}
85-
except ApiException as e:
86-
print("Exception when calling {{classname}}->{{operationId}}: %s\n" % e)
87-
{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
88-
```
89-
90-
## Documentation for API Endpoints
91-
92-
All URIs are relative to *{{basePath}}*
93-
94-
Class | Method | HTTP request | Description
95-
------------ | ------------- | ------------- | -------------
96-
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}}
97-
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
98-
99-
## Documentation For Models
100-
101-
{{#models}}{{#model}} - [{{{classname}}}]({{modelDocPath}}{{{classname}}}.md)
102-
{{/model}}{{/models}}
103-
104-
## Documentation For Authorization
105-
106-
{{^authMethods}} All endpoints do not require authorization.
107-
{{/authMethods}}{{#authMethods}}{{#last}} Authentication schemes defined for the API:{{/last}}{{/authMethods}}
108-
{{#authMethods}}## {{{name}}}
109-
110-
{{#isApiKey}}- **Type**: API key
111-
- **API key parameter name**: {{{keyParamName}}}
112-
- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
113-
{{/isApiKey}}
114-
{{#isBasic}}- **Type**: HTTP basic authentication
115-
{{/isBasic}}
116-
{{#isOAuth}}- **Type**: OAuth
117-
- **Flow**: {{{flow}}}
118-
- **Authorization URL**: {{{authorizationUrl}}}
119-
- **Scopes**: {{^scopes}}N/A{{/scopes}}
120-
{{#scopes}} - **{{{scope}}}**: {{{description}}}
121-
{{/scopes}}
122-
{{/isOAuth}}
123-
124-
{{/authMethods}}
125-
126-
## Author
127-
128-
{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}}
129-
{{/hasMore}}{{/apis}}{{/apiInfo}}
55+
{{> common_README }}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# {{{projectName}}}
2+
{{#appDescription}}
3+
{{{appDescription}}}
4+
{{/appDescription}}
5+
6+
The `{{packageName}}` package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
7+
8+
- API version: {{appVersion}}
9+
- Package version: {{packageVersion}}
10+
{{^hideGenerationTimestamp}}
11+
- Build date: {{generatedDate}}
12+
{{/hideGenerationTimestamp}}
13+
- Build package: {{generatorClass}}
14+
{{#infoUrl}}
15+
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
16+
{{/infoUrl}}
17+
18+
## Requirements.
19+
20+
Python 2.7 and 3.4+
21+
22+
## Installation & Usage
23+
24+
This python library package is generated without supporting files like setup.py or requirements files
25+
26+
To be able to use it, you will need these dependencies in your own package that uses this library:
27+
28+
* urllib3 >= 1.15
29+
* six >= 1.10
30+
* certifi
31+
* python-dateutil
32+
{{#asyncio}}
33+
* aiohttp
34+
{{/asyncio}}
35+
{{#tornado}}
36+
* tornado>=4.2,<5
37+
{{/tornado}}
38+
39+
## Getting Started
40+
41+
In your own code, to use this library to connect and interact with {{{projectName}}},
42+
you can run the following:
43+
44+
{{> common_README }}

modules/openapi-generator/src/main/resources/python/__init__package.mustache

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
from __future__ import absolute_import
88

9+
__version__ = "{{packageVersion}}"
10+
911
# import apis into sdk package
1012
{{#apiInfo}}{{#apis}}from {{apiPackage}}.{{classVarName}} import {{classname}}
1113
{{/apis}}{{/apiInfo}}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
```python
2+
from __future__ import print_function
3+
import time
4+
import {{{packageName}}}
5+
from {{{packageName}}}.rest import ApiException
6+
from pprint import pprint
7+
{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}}
8+
# Configure HTTP basic authorization: {{{name}}}
9+
configuration = {{{packageName}}}.Configuration()
10+
configuration.username = 'YOUR_USERNAME'
11+
configuration.password = 'YOUR_PASSWORD'{{/isBasic}}{{#isApiKey}}
12+
# Configure API key authorization: {{{name}}}
13+
configuration = {{{packageName}}}.Configuration()
14+
configuration.api_key['{{{keyParamName}}}'] = 'YOUR_API_KEY'
15+
# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
16+
# configuration.api_key_prefix['{{{keyParamName}}}'] = 'Bearer'{{/isApiKey}}{{#isOAuth}}
17+
# Configure OAuth2 access token for authorization: {{{name}}}
18+
configuration = {{{packageName}}}.Configuration()
19+
configuration.access_token = 'YOUR_ACCESS_TOKEN'{{/isOAuth}}{{/authMethods}}
20+
{{/hasAuthMethods}}
21+
22+
# create an instance of the API class
23+
api_instance = {{{packageName}}}.{{{classname}}}({{{packageName}}}.ApiClient(configuration))
24+
{{#allParams}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}
25+
{{/allParams}}
26+
27+
try:
28+
{{#summary}} # {{{.}}}
29+
{{/summary}} {{#returnType}}api_response = {{/returnType}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}}
30+
pprint(api_response){{/returnType}}
31+
except ApiException as e:
32+
print("Exception when calling {{classname}}->{{operationId}}: %s\n" % e)
33+
{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
34+
```
35+
36+
## Documentation for API Endpoints
37+
38+
All URIs are relative to *{{basePath}}*
39+
40+
Class | Method | HTTP request | Description
41+
------------ | ------------- | ------------- | -------------
42+
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}}
43+
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
44+
45+
## Documentation For Models
46+
47+
{{#models}}{{#model}} - [{{{classname}}}]({{modelDocPath}}{{{classname}}}.md)
48+
{{/model}}{{/models}}
49+
50+
## Documentation For Authorization
51+
52+
{{^authMethods}} All endpoints do not require authorization.
53+
{{/authMethods}}{{#authMethods}}{{#last}} Authentication schemes defined for the API:{{/last}}{{/authMethods}}
54+
{{#authMethods}}## {{{name}}}
55+
56+
{{#isApiKey}}- **Type**: API key
57+
- **API key parameter name**: {{{keyParamName}}}
58+
- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
59+
{{/isApiKey}}
60+
{{#isBasic}}- **Type**: HTTP basic authentication
61+
{{/isBasic}}
62+
{{#isOAuth}}- **Type**: OAuth
63+
- **Flow**: {{{flow}}}
64+
- **Authorization URL**: {{{authorizationUrl}}}
65+
- **Scopes**: {{^scopes}}N/A{{/scopes}}
66+
{{#scopes}} - **{{{scope}}}**: {{{description}}}
67+
{{/scopes}}
68+
{{/isOAuth}}
69+
70+
{{/authMethods}}
71+
72+
## Author
73+
74+
{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}}
75+
{{/hasMore}}{{/apis}}{{/apiInfo}}

modules/openapi-generator/src/test/java/org/openapitools/codegen/options/PythonClientOptionsProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public Map<String, String> createOptions() {
4444
.put(CodegenConstants.PACKAGE_VERSION, PACKAGE_VERSION_VALUE)
4545
.put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, "true")
4646
.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "true")
47+
.put(CodegenConstants.SOURCECODEONLY_GENERATION, "false")
4748
.put(CodegenConstants.LIBRARY, "urllib3")
4849
.build();
4950
}

samples/client/petstore/python-asyncio/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,4 @@ Class | Method | HTTP request | Description
179179

180180

181181

182+

0 commit comments

Comments
 (0)