python: enable more mypy checks 1/n (#17556)

* python: more mypy checks

* mypy: check_untyped_defs

* mypy: disallow_subclassing_any

* mypy: disallow_untyped_decorators

* mypy: disallow_any_generics
This commit is contained in:
Jonathan Ballet
2024-01-09 09:45:05 +01:00
committed by GitHub
parent c041d7e12f
commit df7976c1a3
234 changed files with 992 additions and 628 deletions

View File

@@ -18,7 +18,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
from typing_extensions import Annotated
from openapi_client.api_client import ApiClient
from openapi_client.api_client import ApiClient, RequestSerialized
from openapi_client.api_response import ApiResponse
from openapi_client.rest import RESTResponseType
@@ -227,7 +227,7 @@ class AuthApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -470,7 +470,7 @@ class AuthApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None

View File

@@ -23,7 +23,7 @@ from typing_extensions import Annotated
from openapi_client.models.pet import Pet
from openapi_client.models.tag import Tag
from openapi_client.api_client import ApiClient
from openapi_client.api_client import ApiClient, RequestSerialized
from openapi_client.api_response import ApiResponse
from openapi_client.rest import RESTResponseType
@@ -232,7 +232,7 @@ class BodyApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -487,7 +487,7 @@ class BodyApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -762,7 +762,7 @@ class BodyApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -1033,7 +1033,7 @@ class BodyApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -1303,7 +1303,7 @@ class BodyApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -1573,7 +1573,7 @@ class BodyApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -1843,7 +1843,7 @@ class BodyApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -2113,7 +2113,7 @@ class BodyApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -2383,7 +2383,7 @@ class BodyApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None

View File

@@ -20,7 +20,7 @@ from typing_extensions import Annotated
from pydantic import StrictBool, StrictInt, StrictStr
from typing import Optional
from openapi_client.api_client import ApiClient
from openapi_client.api_client import ApiClient, RequestSerialized
from openapi_client.api_response import ApiResponse
from openapi_client.rest import RESTResponseType
@@ -268,7 +268,7 @@ class FormApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -607,7 +607,7 @@ class FormApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None

View File

@@ -21,7 +21,7 @@ from pydantic import StrictBool, StrictInt, StrictStr, field_validator
from typing import Optional
from openapi_client.models.string_enum_ref import StringEnumRef
from openapi_client.api_client import ApiClient
from openapi_client.api_client import ApiClient, RequestSerialized
from openapi_client.api_response import ApiResponse
from openapi_client.rest import RESTResponseType
@@ -295,7 +295,7 @@ class HeaderApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None

View File

@@ -20,7 +20,7 @@ from typing_extensions import Annotated
from pydantic import StrictInt, StrictStr, field_validator
from openapi_client.models.string_enum_ref import StringEnumRef
from openapi_client.api_client import ApiClient
from openapi_client.api_client import ApiClient, RequestSerialized
from openapi_client.api_response import ApiResponse
from openapi_client.rest import RESTResponseType
@@ -281,7 +281,7 @@ class PathApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None

View File

@@ -24,7 +24,7 @@ from openapi_client.models.pet import Pet
from openapi_client.models.string_enum_ref import StringEnumRef
from openapi_client.models.test_query_style_form_explode_true_array_string_query_object_parameter import TestQueryStyleFormExplodeTrueArrayStringQueryObjectParameter
from openapi_client.api_client import ApiClient
from openapi_client.api_client import ApiClient, RequestSerialized
from openapi_client.api_response import ApiResponse
from openapi_client.rest import RESTResponseType
@@ -259,7 +259,7 @@ class QueryApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -548,7 +548,7 @@ class QueryApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -859,7 +859,7 @@ class QueryApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -1126,7 +1126,7 @@ class QueryApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -1385,7 +1385,7 @@ class QueryApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -1644,7 +1644,7 @@ class QueryApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -1903,7 +1903,7 @@ class QueryApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None
@@ -2162,7 +2162,7 @@ class QueryApi:
_content_type,
_headers,
_host_index,
) -> Tuple:
) -> RequestSerialized:
_host = None

View File

@@ -22,10 +22,10 @@ import re
import tempfile
from urllib.parse import quote
from typing import Tuple, Optional, List
from typing import Tuple, Optional, List, Dict
from openapi_client.configuration import Configuration
from openapi_client.api_response import ApiResponse
from openapi_client.api_response import ApiResponse, T as ApiResponseT
import openapi_client.models
from openapi_client import rest
from openapi_client.exceptions import (
@@ -38,6 +38,7 @@ from openapi_client.exceptions import (
ServiceException
)
RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]]
class ApiClient:
"""Generic API client for OpenAPI client library builds.
@@ -147,7 +148,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.
@@ -280,8 +281,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.
@@ -402,12 +403,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()}
@@ -435,7 +440,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:
@@ -465,7 +470,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:
@@ -650,10 +655,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:

View File

@@ -15,8 +15,10 @@
import copy
import logging
from logging import FileHandler
import multiprocessing
import sys
from typing import Optional
import urllib3
import http.client as httplib
@@ -133,7 +135,7 @@ conf = openapi_client.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
@@ -173,7 +175,7 @@ conf = openapi_client.Configuration(
cpu_count * 5 is used as default value to increase performance.
"""
self.proxy = None
self.proxy: Optional[str] = None
"""Proxy URL
"""
self.proxy_headers = None

View File

@@ -73,7 +73,7 @@ class Bird(BaseModel):
return _dict
@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 Bird from a dict"""
if obj is None:
return None

View File

@@ -73,7 +73,7 @@ class Category(BaseModel):
return _dict
@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 Category from a dict"""
if obj is None:
return None

View File

@@ -76,7 +76,7 @@ class DataQuery(Query):
return _dict
@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 DataQuery from a dict"""
if obj is None:
return None

View File

@@ -106,7 +106,7 @@ class DefaultValue(BaseModel):
return _dict
@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 DefaultValue from a dict"""
if obj is None:
return None

View File

@@ -75,7 +75,7 @@ class NumberPropertiesOnly(BaseModel):
return _dict
@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 NumberPropertiesOnly from a dict"""
if obj is None:
return None

View File

@@ -99,7 +99,7 @@ class Pet(BaseModel):
return _dict
@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 Pet from a dict"""
if obj is None:
return None

View File

@@ -84,7 +84,7 @@ class Query(BaseModel):
return _dict
@classmethod
def from_dict(cls, obj: Dict) -> Optional[Self]:
def from_dict(cls, obj: Dict[str, Any]) -> Optional[Self]:
"""Create an instance of Query from a dict"""

View File

@@ -73,7 +73,7 @@ class Tag(BaseModel):
return _dict
@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 Tag from a dict"""
if obj is None:
return None

View File

@@ -75,7 +75,7 @@ class TestQueryStyleDeepObjectExplodeTrueObjectAllOfQueryObjectParameter(BaseMod
return _dict
@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 TestQueryStyleDeepObjectExplodeTrueObjectAllOfQueryObjectParameter from a dict"""
if obj is None:
return None

View File

@@ -72,7 +72,7 @@ class TestQueryStyleFormExplodeTrueArrayStringQueryObjectParameter(BaseModel):
return _dict
@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 TestQueryStyleFormExplodeTrueArrayStringQueryObjectParameter from a dict"""
if obj is None:
return None

View File

@@ -213,14 +213,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

View File

@@ -38,3 +38,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

View File

@@ -85,7 +85,7 @@ class TestManual(unittest.TestCase):
datetime_format_backup = api_instance.api_client.configuration.datetime_format # backup dateime_format
api_instance.api_client.configuration.datetime_format = "%Y-%m-%d %a %H:%M:%S%Z"
datetime_query = datetime.datetime.fromisoformat('2013-10-20T19:20:30-05:00') # datetime | (optional)
date_query = '2013-10-20' # date | (optional)
date_query = datetime.date(2013, 10, 20) # date | (optional)
string_query = 'string_query_example' # str | (optional)
# Test query parameter(s)
@@ -99,7 +99,7 @@ class TestManual(unittest.TestCase):
def testDateTimeQueryWithDateTime(self):
api_instance = openapi_client.QueryApi()
datetime_query = datetime.datetime.fromisoformat('2013-10-20T19:20:30-05:00') # datetime | (optional)
date_query = '2013-10-20' # date | (optional)
date_query = datetime.date(2013, 10, 20) # date | (optional)
string_query = 'string_query_example' # str | (optional)
# Test query parameter(s)
@@ -116,12 +116,14 @@ class TestManual(unittest.TestCase):
def testNumberPropertiesOnly(self):
n = openapi_client.NumberPropertiesOnly.from_json('{"number": 123, "float": 456, "double": 34}')
assert n is not None
self.assertEqual(n.number, 123)
# TODO: pydantic v2: this field name override the default `float` type
# self.assertEqual(n.float, 456)
self.assertEqual(n.double, 34)
n = openapi_client.NumberPropertiesOnly.from_json('{"number": 123.1, "float": 456.2, "double": 34.3}')
assert n is not None
self.assertEqual(n.number, 123.1)
# TODO: pydantic v2: this field name override the default `float` type
# self.assertEqual(n.float, 456.2)
@@ -187,11 +189,14 @@ class TestManual(unittest.TestCase):
" \"status\": \"available\",\n"
" \"tags\": [{\"id\": 1, \"name\": \"None\"}]}")
pet = openapi_client.Pet.from_json(json_str)
assert pet is not None
self.assertEqual(pet.id, 1)
self.assertEqual(pet.status, "available")
self.assertEqual(pet.photo_urls, ["string"])
assert pet.tags is not None
self.assertEqual(pet.tags[0].id, 1)
self.assertEqual(pet.tags[0].name, "None")
assert pet.category is not None
self.assertEqual(pet.category.id, 1)
# test to_json
self.assertEqual(pet.to_json(),
@@ -205,11 +210,14 @@ class TestManual(unittest.TestCase):
# test from_dict
pet2 = openapi_client.Pet.from_dict(pet.to_dict())
assert pet2 is not None
self.assertEqual(pet2.id, 1)
self.assertEqual(pet2.status, "available")
self.assertEqual(pet2.photo_urls, ["string"])
assert pet2.tags is not None
self.assertEqual(pet2.tags[0].id, 1)
self.assertEqual(pet2.tags[0].name, "None")
assert pet2.category is not None
self.assertEqual(pet2.category.id, 1)
def test_parameters_to_url_query_boolean_value(self):