Skip to content

Commit

Permalink
[python-experimental] Quicken package loading (#6437)
Browse files Browse the repository at this point in the history
* apis and models contains all apis and models, omits loading them in the package namespace

* Runs git add -a and commits it

* Fixes test_outer_enum.py

* Fixes test_fruit.py

* Updates test_fruit and test_mammal

* Fixes test_parent_pet

* Updates test_discard_unknown_properties.py

* Updates test_deserialization.py

* Updates v2 docs md files for apis + the readme

* Fixes v2 tests

* v2 doc updates

* Updates v3 docs

* Reverts python_doc_auth_partial.mustache

* Adds sys to v3 tests

* Adds FILES update

Co-authored-by: Justin Black <justinblack@justins-air.lan>
  • Loading branch information
spacether and Justin Black authored Jun 1, 2020
1 parent 6783b90 commit d8c4223
Show file tree
Hide file tree
Showing 363 changed files with 2,503 additions and 2,005 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ public PythonClientExperimentalCodegen() {
apiDocTemplateFiles.remove("api_doc.mustache");
apiDocTemplateFiles.put("python-experimental/api_doc.mustache", ".md");

apiTestTemplateFiles.remove("api_test.mustache", ".py");
apiTestTemplateFiles.put("python-experimental/api_test.mustache", ".py");

modelDocTemplateFiles.remove("model_doc.mustache");
modelDocTemplateFiles.put("python-experimental/model_doc.mustache", ".md");

Expand All @@ -123,18 +126,22 @@ public void processOpts() {
this.setLegacyDiscriminatorBehavior(false);

super.processOpts();
modelPackage = packageName + "." + "model";

supportingFiles.remove(new SupportingFile("api_client.mustache", packagePath(), "api_client.py"));
supportingFiles.add(new SupportingFile("python-experimental/api_client.mustache", packagePath(), "api_client.py"));

supportingFiles.add(new SupportingFile("python-experimental/model_utils.mustache", packagePath(), "model_utils.py"));

supportingFiles.remove(new SupportingFile("__init__model.mustache", packagePath() + File.separatorChar + "models", "__init__.py"));
supportingFiles.add(new SupportingFile("python-experimental/__init__model.mustache", packagePath() + File.separatorChar + "models", "__init__.py"));
supportingFiles.add(new SupportingFile("python-experimental/__init__model.mustache", packagePath() + File.separatorChar + "model", "__init__.py"));

supportingFiles.remove(new SupportingFile("__init__package.mustache", packagePath(), "__init__.py"));
supportingFiles.add(new SupportingFile("python-experimental/__init__package.mustache", packagePath(), "__init__.py"));

// add the models and apis folders
supportingFiles.add(new SupportingFile("python-experimental/__init__models.mustache", packagePath() + File.separatorChar + "models", "__init__.py"));
supportingFiles.add(new SupportingFile("python-experimental/__init__apis.mustache", packagePath() + File.separatorChar + "apis", "__init__.py"));

// Generate the 'signing.py' module, but only if the 'HTTP signature' security scheme is specified in the OAS.
Map<String, SecurityScheme> securitySchemeMap = openAPI != null ?
Expand Down Expand Up @@ -518,9 +525,9 @@ public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, S
// set the example value
if (modelProp.isEnum) {
String value = modelProp._enum.get(0).toString();
result.example = this.packageName + "." + result.baseType + "(" + toEnumValue(value, simpleDataType) + ")";
result.example = result.dataType + "(" + toEnumValue(value, simpleDataType) + ")";
} else {
result.example = this.packageName + "." + result.baseType + "(" + result.example + ")";
result.example = result.dataType + "(" + result.example + ")";
}
} else if (!result.isPrimitiveType) {
// fix the baseType for the api docs so the .md link to the class's documentation file is correct
Expand Down Expand Up @@ -1064,7 +1071,7 @@ public void setParameterExampleValue(CodegenParameter p) {
example = "'" + escapeText(example) + "'";
} else if (!languageSpecificPrimitives.contains(type)) {
// type is a model class, e.g. user.User
example = this.packageName + "." + getPythonClassName(type) + "()";
example = type + "()";
} else {
LOGGER.warn("Type " + type + " not handled properly in setParameterExampleValue");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ from __future__ import print_function
import time
import {{{packageName}}}
from pprint import pprint
{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}
{{#apiInfo}}
{{#apis}}
{{#-first}}
from {{apiPackage}} import {{classVarName}}
{{#imports}}
{{{import}}}
{{/imports}}
{{#operations}}
{{#operation}}
{{#-first}}
{{> python_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 = {{{packageName}}}.{{{classname}}}(api_client)
api_instance = {{classVarName}}.{{{classname}}}(api_client)
{{#allParams}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}
{{/allParams}}

Expand All @@ -20,7 +29,12 @@ with {{{packageName}}}.ApiClient(configuration) as api_client:
pprint(api_response){{/returnType}}
except {{{packageName}}}.ApiException as e:
print("Exception when calling {{classname}}->{{operationId}}: %s\n" % e)
{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}}
{{/-first}}
{{/operation}}
{{/operations}}
{{/-first}}
{{/apis}}
{{/apiInfo}}
```

## Documentation for API Endpoints
Expand Down Expand Up @@ -77,3 +91,22 @@ Class | Method | HTTP request | Description

{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}}
{{/hasMore}}{{/apis}}{{/apiInfo}}

## 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}}}.api.default_api import DefaultApi`
- `from {{{packageName}}}.model.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,3 @@
# 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 models from one package, import them with
# from {{packageName}.apis import DefaultApi, PetApi
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# coding: utf-8

# flake8: noqa

# import all apis into this package
# if you have many ampis here with many many models used in each api this may
# raise a RecursionError
# to avoid this, import only the api that you directly need like:
# from {{packagename}}.api.pet_api import PetApi
# or import this package, but before doing it, use:
# import sys
# sys.setrecursionlimit(n)

# import apis into api package
{{#apiInfo}}
{{#apis}}
from {{apiPackage}}.{{classVarName}} import {{classname}}
{{/apis}}
{{/apiInfo}}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# coding: utf-8

# flake8: noqa
{{>partial_header}}

# 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 {{modelPackage}}.pet import Pet
# or import this package, but before doing it, use:
# import sys
# sys.setrecursionlimit(n)

{{#models}}
{{#model}}
from {{modelPackage}}.{{classFilename}} import {{unescapedDescription}}
{{/model}}
{{/models}}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@ from __future__ import absolute_import

__version__ = "{{packageVersion}}"

# import apis into sdk package
{{#apiInfo}}
{{#apis}}
from {{apiPackage}}.{{classVarName}} import {{classname}}
{{/apis}}
{{/apiInfo}}

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

Expand All @@ -26,14 +19,8 @@ from {{packageName}}.signing import HttpSigningConfiguration

# 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

# import models into sdk package
{{#models}}
{{#model}}
from {{modelPackage}}.{{classFilename}} import {{unescapedDescription}}
{{/model}}
{{/models}}
from {{packageName}}.exceptions import ApiException
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
from __future__ import print_function
import time
import {{{packageName}}}
from {{apiPackage}} import {{classVarName}}
{{#imports}}
{{{.}}}
{{/imports}}
from pprint import pprint
{{> python_doc_auth_partial}}
# Enter a context with an instance of the API client
Expand All @@ -12,7 +16,7 @@ with {{{packageName}}}.ApiClient(configuration) as api_client:
with {{{packageName}}}.ApiClient() as api_client:
{{/hasAuthMethods}}
# Create an instance of the API class
api_instance = {{{packageName}}}.{{{classname}}}(api_client)
api_instance = {{classVarName}}.{{{classname}}}(api_client)
{{#requiredParams}}{{^defaultValue}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}
{{/defaultValue}}{{/requiredParams}}{{#optionalParams}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} if omitted the server will use the default value of {{{defaultValue}}}{{/defaultValue}}
{{/optionalParams}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# coding: utf-8

{{>partial_header}}

from __future__ import absolute_import

import unittest

import {{packageName}}
from {{apiPackage}}.{{classVarName}} import {{classname}} # noqa: E501


class {{#operations}}Test{{classname}}(unittest.TestCase):
"""{{classname}} unit test stubs"""

def setUp(self):
self.api = {{classname}}() # noqa: E501

def tearDown(self):
pass

{{#operation}}
def test_{{operationId}}(self):
"""Test case for {{{operationId}}}

{{#summary}}
{{{summary}}} # noqa: E501
{{/summary}}
"""
pass

{{/operation}}
{{/operations}}

if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
{{>partial_header}}

from __future__ import absolute_import

import sys
import unittest

import {{packageName}}
{{#models}}
{{#model}}
import {{packageName}}
{{#imports}}
{{{.}}}
{{/imports}}
from {{modelPackage}}.{{classFilename}} import {{unescapedDescription}}


class Test{{unescapedDescription}}(unittest.TestCase):
Expand All @@ -23,7 +27,7 @@ class Test{{unescapedDescription}}(unittest.TestCase):
def test{{unescapedDescription}}(self):
"""Test {{unescapedDescription}}"""
# FIXME: construct object with mandatory attributes with example values
# model = {{packageName}}.{{unescapedDescription}}() # noqa: E501
# model = {{unescapedDescription}}() # noqa: E501
pass

{{/model}}
Expand Down
Loading

0 comments on commit d8c4223

Please sign in to comment.