Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ from typing_extensions import Annotated
{{import}}
{{/imports}}

from {{packageName}}.api_client import ApiClient
from {{packageName}}.api_client import ApiClient, RequestSerialized
from {{packageName}}.api_response import ApiResponse
from {{packageName}}.rest import RESTResponseType

Expand Down Expand Up @@ -77,7 +77,7 @@ class {{classname}}:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:

{{#servers.0}}
_hosts = [{{#servers}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import re
import tempfile

from urllib.parse import quote
from typing import Tuple, Optional, List
from typing import Tuple, Optional, List, Dict
{{#tornado}}
import tornado.gen
{{/tornado}}

from {{packageName}}.configuration import Configuration
from {{packageName}}.api_response import ApiResponse
from {{packageName}}.api_response import ApiResponse, T as ApiResponseT
import {{modelPackage}}
from {{packageName}} import rest
from {{packageName}}.exceptions import (
Expand All @@ -30,6 +30,7 @@ from {{packageName}}.exceptions import (
ServiceException
)

RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]]

class ApiClient:
"""Generic API client for OpenAPI client library builds.
Expand Down Expand Up @@ -151,7 +152,7 @@ class ApiClient:
collection_formats=None,
_host=None,
_request_auth=None
) -> Tuple:
) -> RequestSerialized:

"""Builds the HTTP request params needed by the request.
:param method: Method to call.
Expand Down Expand Up @@ -287,8 +288,8 @@ class ApiClient:
def response_deserialize(
self,
response_data: rest.RESTResponse,
response_types_map=None
) -> ApiResponse:
response_types_map: Optional[Dict[str, ApiResponseT]]=None
) -> ApiResponse[ApiResponseT]:
"""Deserializes response into an object.
:param response_data: RESTResponse object to be deserialized.
:param response_types_map: dict of response types.
Expand Down Expand Up @@ -409,12 +410,16 @@ class ApiClient:

if isinstance(klass, str):
if klass.startswith('List['):
sub_kls = re.match(r'List\[(.*)]', klass).group(1)
m = re.match(r'List\[(.*)]', klass)
assert m is not None, "Malformed List type definition"
sub_kls = m.group(1)
return [self.__deserialize(sub_data, sub_kls)
for sub_data in data]

if klass.startswith('Dict['):
sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2)
m = re.match(r'Dict\[([^,]*), (.*)]', klass)
assert m is not None, "Malformed Dict type definition"
sub_kls = m.group(2)
return {k: self.__deserialize(v, sub_kls)
for k, v in data.items()}

Expand Down Expand Up @@ -442,7 +447,7 @@ class ApiClient:
:param dict collection_formats: Parameter collection formats
:return: Parameters as list of tuples, collections formatted
"""
new_params = []
new_params: List[Tuple[str, str]] = []
if collection_formats is None:
collection_formats = {}
for k, v in params.items() if isinstance(params, dict) else params:
Expand Down Expand Up @@ -472,7 +477,7 @@ class ApiClient:
:param dict collection_formats: Parameter collection formats
:return: URL query string (e.g. a=Hello%20World&b=123)
"""
new_params = []
new_params: List[Tuple[str, str]] = []
if collection_formats is None:
collection_formats = {}
for k, v in params.items() if isinstance(params, dict) else params:
Expand Down Expand Up @@ -666,10 +671,12 @@ class ApiClient:

content_disposition = response.getheader("Content-Disposition")
if content_disposition:
filename = re.search(
m = re.search(
r'filename=[\'"]?([^\'"\s]+)[\'"]?',
content_disposition
).group(1)
)
assert m is not None, "Unexpected 'content-disposition' header value"
filename = m.group(1)
path = os.path.join(os.path.dirname(path), filename)

with open(path, "wb") as f:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import io
import json
import re
import ssl
from typing import Optional
from typing import Optional, Union

import aiohttp
import aiohttp_retry
Expand Down Expand Up @@ -189,6 +189,7 @@ class RESTClientObject:
declared content type."""
raise ApiException(status=0, reason=msg)

pool_manager: Union[aiohttp.ClientSession, aiohttp_retry.RetryClient]
if self.retry_client is not None and method in ALLOW_RETRY_METHODS:
pool_manager = self.retry_client
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

import copy
import logging
from logging import FileHandler
{{^asyncio}}
import multiprocessing
{{/asyncio}}
import sys
from typing import Optional
import urllib3

import http.client as httplib
Expand Down Expand Up @@ -204,7 +206,7 @@ conf = {{{packageName}}}.Configuration(
self.logger_stream_handler = None
"""Log stream handler
"""
self.logger_file_handler = None
self.logger_file_handler: Optional[FileHandler] = None
"""Log file handler
"""
self.logger_file = None
Expand Down Expand Up @@ -252,7 +254,7 @@ conf = {{{packageName}}}.Configuration(
"""
{{/asyncio}}

self.proxy = None
self.proxy: Optional[str] = None
"""Proxy URL
"""
self.proxy_headers = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
return v

@classmethod
def from_dict(cls, obj: dict) -> Self:
def from_dict(cls, obj: Dict[str, Any]) -> Self:
return cls.from_json(json.dumps(obj))

@classmethod
Expand Down Expand Up @@ -159,7 +159,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
else:
return json.dumps(self.actual_instance)

def to_dict(self) -> Optional[Union[Dict, {{#anyOf}}{{.}}{{^-last}}, {{/-last}}{{/anyOf}}]]:
def to_dict(self) -> Optional[Union[Dict[str, Any], {{#anyOf}}{{.}}{{^-last}}, {{/-last}}{{/anyOf}}]]:
"""Returns the dict representation of the actual instance"""
if self.actual_instance is None:
return None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
}

@classmethod
def get_discriminator_value(cls, obj: Dict) -> Optional[str]:
def get_discriminator_value(cls, obj: Dict[str, Any]) -> Optional[str]:
"""Returns the discriminator value (object type) of the data"""
discriminator_value = obj[cls.__discriminator_property_name]
if discriminator_value:
Expand Down Expand Up @@ -236,7 +236,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}

{{#hasChildren}}
@classmethod
def from_dict(cls, obj: Dict) -> Optional[{{#discriminator}}Union[{{#children}}Self{{^-last}}, {{/-last}}{{/children}}]{{/discriminator}}{{^discriminator}}Self{{/discriminator}}]:
def from_dict(cls, obj: Dict[str, Any]) -> Optional[{{#discriminator}}Union[{{#children}}Self{{^-last}}, {{/-last}}{{/children}}]{{/discriminator}}{{^discriminator}}Self{{/discriminator}}]:
"""Create an instance of {{{classname}}} from a dict"""
{{#discriminator}}
# look up the object type based on discriminator mapping
Expand All @@ -252,7 +252,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
{{/hasChildren}}
{{^hasChildren}}
@classmethod
def from_dict(cls, obj: Optional[Dict]) -> Optional[Self]:
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
"""Create an instance of {{{classname}}} from a dict"""
if obj is None:
return None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,16 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
return v

@classmethod
def from_dict(cls, obj: dict) -> Self:
def from_dict(cls, obj: Union[str, Dict[str, Any]]) -> Self:
return cls.from_json(json.dumps(obj))

@classmethod
{{#isNullable}}
def from_json(cls, json_str: Optional[str]) -> Self:
{{/isNullable}}
{{^isNullable}}
def from_json(cls, json_str: str) -> Self:
{{/isNullable}}
"""Returns the object represented by the json string"""
instance = cls.model_construct()
{{#isNullable}}
Expand Down Expand Up @@ -180,7 +185,7 @@ class {{classname}}({{#parent}}{{{.}}}{{/parent}}{{^parent}}BaseModel{{/parent}}
else:
return json.dumps(self.actual_instance)

def to_dict(self) -> Optional[Union[Dict, {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}]]:
def to_dict(self) -> Optional[Union[Dict[str, Any], {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}]]:
"""Returns the dict representation of the actual instance"""
if self.actual_instance is None:
return None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,34 @@ files = [
#"test", # auto-generated tests
"tests", # hand-written tests
]
# TODO: enable "strict" once all these individual checks are passing
# strict = true

# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true

## Getting these passing should be easy
strict_equality = true
strict_concatenate = true

## Strongly recommend enabling this one as soon as you can
check_untyped_defs = true

## These shouldn't be too much additional work, but may be tricky to
## get passing if you use a lot of untyped libraries
disallow_subclassing_any = true
disallow_untyped_decorators = true
disallow_any_generics = true

### These next few are various gradations of forcing use of type annotations
#disallow_untyped_calls = true
#disallow_incomplete_defs = true
#disallow_untyped_defs = true
#
### This one isn't too hard to get passing, but return on investment is lower
#no_implicit_reexport = true
#
### This one can be tricky to get passing if you use a lot of untyped libraries
#warn_return_any = true
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,13 @@ class RESTClientObject:
preload_content=False
)
# Pass a `string` parameter directly in the body to support
# other content types than Json when `body` argument is
# provided in serialized form
# other content types than JSON when `body` argument is
# provided in serialized form.
elif isinstance(body, str) or isinstance(body, bytes):
request_body = body
r = self.pool_manager.request(
method,
url,
body=request_body,
body=body,
timeout=timeout,
headers=headers,
preload_content=False
Expand Down
Loading