mypy: Address issues with top-level files
Address issues in all files in the 'openstack' directory as well as the 'openstack/common', 'openstack/config' and 'openstack/test' directories. With this done, we can start introducing mypy iteratively. Note that we disable type hints in Sphinx. This is necessary because Sphinx apparently can't tell the difference between 'Type' from 'typing' and 'Type' from 'openstack.block_storage.v[23].Type', which causes a build warning. This is okay since typing makes docs too noisy anyway. Change-Id: Ia91c5da779b5b68c408dfc934a21d77e9ca2f550 Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
parent
3163c7597d
commit
2a8627d4f1
@ -60,7 +60,13 @@ add_module_names = True
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'native'
|
||||
|
||||
autodoc_member_order = "bysource"
|
||||
autodoc_member_order = 'bysource'
|
||||
|
||||
# Include both the class and __init__ docstrings when describing the class
|
||||
autoclass_content = 'both'
|
||||
|
||||
# Don't document type hints as they're too noisy
|
||||
autodoc_typehints = 'none'
|
||||
|
||||
# Locations to exclude when looking for source files.
|
||||
exclude_patterns = []
|
||||
@ -70,8 +76,7 @@ exclude_patterns = []
|
||||
# Don't let openstackdocstheme insert TOCs automatically.
|
||||
theme_include_auto_toc = False
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'openstacksdkdoc'
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
@ -91,6 +96,3 @@ latex_elements = {'maxlistdepth': 10}
|
||||
|
||||
# Disable usage of xindy https://bugzilla.redhat.com/show_bug.cgi?id=1643664
|
||||
latex_use_xindy = False
|
||||
|
||||
# Include both the class and __init__ docstrings when describing the class
|
||||
autoclass_content = "both"
|
||||
|
@ -9,12 +9,17 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from openstack import exceptions
|
||||
from openstack import resource
|
||||
from openstack import utils
|
||||
|
||||
|
||||
class MetadataMixin:
|
||||
id: resource.Body
|
||||
base_path: str
|
||||
_body: resource._ComponentManager
|
||||
|
||||
#: *Type: list of tag strings*
|
||||
metadata = resource.Body('metadata', type=dict)
|
||||
|
||||
|
@ -9,6 +9,9 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import typing as ty
|
||||
|
||||
from openstack import exceptions
|
||||
from openstack import resource
|
||||
|
||||
@ -88,7 +91,7 @@ class QuotaSet(resource.Resource):
|
||||
body.pop("self", None)
|
||||
|
||||
# Process body_attrs to strip usage and reservation out
|
||||
normalized_attrs = dict(
|
||||
normalized_attrs: ty.Dict[str, ty.Any] = dict(
|
||||
reservation={},
|
||||
usage={},
|
||||
)
|
||||
|
@ -9,12 +9,21 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from openstack import exceptions
|
||||
from openstack import resource
|
||||
from openstack import utils
|
||||
|
||||
|
||||
class TagMixin:
|
||||
id: resource.Body
|
||||
base_path: str
|
||||
_body: resource._ComponentManager
|
||||
|
||||
@classmethod
|
||||
def _get_session(cls, session):
|
||||
...
|
||||
|
||||
_tag_query_parameters = {
|
||||
'tags': 'tags',
|
||||
'any_tags': 'tags-any',
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
import copy
|
||||
import os.path
|
||||
import typing as ty
|
||||
import urllib
|
||||
import warnings
|
||||
|
||||
@ -195,7 +196,7 @@ def from_conf(conf, session=None, service_types=None, **kwargs):
|
||||
),
|
||||
)
|
||||
continue
|
||||
opt_dict = {}
|
||||
opt_dict: ty.Dict[str, str] = {}
|
||||
# Populate opt_dict with (appropriately processed) Adapter conf opts
|
||||
try:
|
||||
ks_load_adap.process_conf_options(conf[project_name], opt_dict)
|
||||
|
@ -21,6 +21,7 @@ import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import typing as ty
|
||||
import warnings
|
||||
|
||||
import appdirs
|
||||
@ -129,7 +130,7 @@ def _fix_argv(argv):
|
||||
argv[index] = "=".join(split_args)
|
||||
# Save both for later so we can throw an error about dupes
|
||||
processed[new].add(orig)
|
||||
overlap = []
|
||||
overlap: ty.List[str] = []
|
||||
for new, old in processed.items():
|
||||
if len(old) > 1:
|
||||
overlap.extend(old)
|
||||
@ -297,8 +298,8 @@ class OpenStackConfig:
|
||||
self._cache_expiration_time = 0
|
||||
self._cache_path = CACHE_PATH
|
||||
self._cache_class = 'dogpile.cache.null'
|
||||
self._cache_arguments = {}
|
||||
self._cache_expirations = {}
|
||||
self._cache_arguments: ty.Dict[str, ty.Any] = {}
|
||||
self._cache_expirations: ty.Dict[str, int] = {}
|
||||
self._influxdb_config = {}
|
||||
if 'cache' in self.cloud_config:
|
||||
cache_settings = _util.normalize_keys(self.cloud_config['cache'])
|
||||
@ -514,8 +515,8 @@ class OpenStackConfig:
|
||||
return self._expand_regions(regions)
|
||||
else:
|
||||
# crappit. we don't have a region defined.
|
||||
new_cloud = dict()
|
||||
our_cloud = self.cloud_config['clouds'].get(cloud, dict())
|
||||
new_cloud: ty.Dict[str, ty.Any] = {}
|
||||
our_cloud = self.cloud_config['clouds'].get(cloud, {})
|
||||
self._expand_vendor_profile(cloud, new_cloud, our_cloud)
|
||||
if 'regions' in new_cloud and new_cloud['regions']:
|
||||
return self._expand_regions(new_cloud['regions'])
|
||||
|
3
openstack/config/vendors/__init__.py
vendored
3
openstack/config/vendors/__init__.py
vendored
@ -15,6 +15,7 @@
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import typing as ty
|
||||
import urllib
|
||||
|
||||
import requests
|
||||
@ -24,7 +25,7 @@ from openstack.config import _util
|
||||
from openstack import exceptions
|
||||
|
||||
_VENDORS_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
_VENDOR_DEFAULTS = {}
|
||||
_VENDOR_DEFAULTS: ty.Dict[str, ty.Dict] = {}
|
||||
_WELL_KNOWN_PATH = "{scheme}://{netloc}/.well-known/openstack/api"
|
||||
|
||||
|
||||
|
@ -209,7 +209,7 @@ try:
|
||||
import importlib.metadata as importlib_metadata
|
||||
except ImportError:
|
||||
# For everyone else
|
||||
import importlib_metadata
|
||||
import importlib_metadata # type: ignore
|
||||
import keystoneauth1.exceptions
|
||||
import requestsexceptions
|
||||
|
||||
|
@ -18,6 +18,7 @@ Exception definitions.
|
||||
|
||||
import json
|
||||
import re
|
||||
import typing as ty
|
||||
|
||||
from requests import exceptions as _rex
|
||||
|
||||
@ -214,6 +215,7 @@ def raise_from_response(response, error_message=None):
|
||||
if response.status_code < 400:
|
||||
return
|
||||
|
||||
cls: ty.Type[SDKException]
|
||||
if response.status_code == 400:
|
||||
cls = BadRequestException
|
||||
elif response.status_code == 403:
|
||||
@ -251,6 +253,7 @@ def raise_from_response(response, error_message=None):
|
||||
message = re.sub(r'<.+?>', '', line.strip())
|
||||
if message not in messages:
|
||||
messages.append(message)
|
||||
|
||||
# Return joined string separated by colons.
|
||||
details = ': '.join(messages)
|
||||
|
||||
|
@ -9,10 +9,8 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from typing import Generic
|
||||
from typing import Optional
|
||||
from typing import Type
|
||||
from typing import TypeVar
|
||||
|
||||
import typing as ty
|
||||
|
||||
from openstack import exceptions
|
||||
from openstack.network.v2 import address_group as _address_group
|
||||
@ -93,11 +91,10 @@ from openstack.network.v2 import (
|
||||
)
|
||||
from openstack.network.v2 import vpn_service as _vpn_service
|
||||
from openstack import proxy
|
||||
|
||||
T = TypeVar('T')
|
||||
from openstack import resource
|
||||
|
||||
|
||||
class Proxy(proxy.Proxy, Generic[T]):
|
||||
class Proxy(proxy.Proxy):
|
||||
_resource_registry = {
|
||||
"address_group": _address_group.AddressGroup,
|
||||
"address_scope": _address_scope.AddressScope,
|
||||
@ -179,24 +176,24 @@ class Proxy(proxy.Proxy, Generic[T]):
|
||||
@proxy._check_resource(strict=False)
|
||||
def _update(
|
||||
self,
|
||||
resource_type: Type[T],
|
||||
resource_type: ty.Type[resource.Resource],
|
||||
value,
|
||||
base_path=None,
|
||||
if_revision=None,
|
||||
**attrs,
|
||||
) -> T:
|
||||
) -> resource.Resource:
|
||||
res = self._get_resource(resource_type, value, **attrs)
|
||||
return res.commit(self, base_path=base_path, if_revision=if_revision)
|
||||
|
||||
@proxy._check_resource(strict=False)
|
||||
def _delete(
|
||||
self,
|
||||
resource_type: Type[T],
|
||||
resource_type: ty.Type[resource.Resource],
|
||||
value,
|
||||
ignore_missing=True,
|
||||
if_revision=None,
|
||||
**attrs,
|
||||
) -> Optional[T]:
|
||||
) -> ty.Optional[resource.Resource]:
|
||||
res = self._get_resource(resource_type, value, **attrs)
|
||||
|
||||
try:
|
||||
|
@ -9,7 +9,8 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from typing import List
|
||||
|
||||
import typing as ty
|
||||
|
||||
from openstack.common import tag
|
||||
from openstack.network.v2 import _base
|
||||
@ -58,7 +59,7 @@ class Port(_base.NetworkResource, tag.TagMixin):
|
||||
# Properties
|
||||
#: Allowed address pairs list. Dictionary key ``ip_address`` is required
|
||||
#: and key ``mac_address`` is optional.
|
||||
allowed_address_pairs: List[dict] = resource.Body(
|
||||
allowed_address_pairs: ty.List[dict] = resource.Body(
|
||||
'allowed_address_pairs', type=list
|
||||
)
|
||||
#: The ID of the host where the port is allocated. In some cases,
|
||||
|
@ -11,11 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
from typing import Generator
|
||||
from typing import Generic
|
||||
from typing import Optional
|
||||
from typing import Type
|
||||
from typing import TypeVar
|
||||
import typing as ty
|
||||
import urllib
|
||||
from urllib.parse import urlparse
|
||||
|
||||
@ -24,7 +20,7 @@ try:
|
||||
|
||||
JSONDecodeError = simplejson.scanner.JSONDecodeError
|
||||
except ImportError:
|
||||
JSONDecodeError = ValueError
|
||||
JSONDecodeError = ValueError # type: ignore
|
||||
import iso8601
|
||||
import jmespath
|
||||
from keystoneauth1 import adapter
|
||||
@ -33,7 +29,8 @@ from openstack import _log
|
||||
from openstack import exceptions
|
||||
from openstack import resource
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
ResourceType = ty.TypeVar('ResourceType', bound=resource.Resource)
|
||||
|
||||
|
||||
# The _check_resource decorator is used on Proxy methods to ensure that
|
||||
@ -74,7 +71,7 @@ def normalize_metric_name(name):
|
||||
return name
|
||||
|
||||
|
||||
class Proxy(adapter.Adapter, Generic[T]):
|
||||
class Proxy(adapter.Adapter):
|
||||
"""Represents a service."""
|
||||
|
||||
retriable_status_codes = None
|
||||
@ -84,7 +81,7 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
``<service-type>_status_code_retries``.
|
||||
"""
|
||||
|
||||
_resource_registry = dict()
|
||||
_resource_registry: ty.Dict[str, ty.Type[resource.Resource]] = {}
|
||||
"""Registry of the supported resourses.
|
||||
|
||||
Dictionary of resource names (key) types (value).
|
||||
@ -431,7 +428,9 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
self, '_connection', getattr(self.session, '_sdk_connection', None)
|
||||
)
|
||||
|
||||
def _get_resource(self, resource_type: Type[T], value, **attrs) -> T:
|
||||
def _get_resource(
|
||||
self, resource_type: ty.Type[ResourceType], value, **attrs
|
||||
) -> ResourceType:
|
||||
"""Get a resource object to work on
|
||||
|
||||
:param resource_type: The type of resource to operate on. This should
|
||||
@ -478,8 +477,12 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
return value
|
||||
|
||||
def _find(
|
||||
self, resource_type: Type[T], name_or_id, ignore_missing=True, **attrs
|
||||
) -> Optional[T]:
|
||||
self,
|
||||
resource_type: ty.Type[ResourceType],
|
||||
name_or_id,
|
||||
ignore_missing=True,
|
||||
**attrs,
|
||||
) -> ty.Optional[ResourceType]:
|
||||
"""Find a resource
|
||||
|
||||
:param name_or_id: The name or ID of a resource to find.
|
||||
@ -500,8 +503,12 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
|
||||
@_check_resource(strict=False)
|
||||
def _delete(
|
||||
self, resource_type: Type[T], value, ignore_missing=True, **attrs
|
||||
):
|
||||
self,
|
||||
resource_type: ty.Type[ResourceType],
|
||||
value,
|
||||
ignore_missing=True,
|
||||
**attrs,
|
||||
) -> ty.Optional[ResourceType]:
|
||||
"""Delete a resource
|
||||
|
||||
:param resource_type: The type of resource to delete. This should
|
||||
@ -538,8 +545,12 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
|
||||
@_check_resource(strict=False)
|
||||
def _update(
|
||||
self, resource_type: Type[T], value, base_path=None, **attrs
|
||||
) -> T:
|
||||
self,
|
||||
resource_type: ty.Type[ResourceType],
|
||||
value,
|
||||
base_path=None,
|
||||
**attrs,
|
||||
) -> ResourceType:
|
||||
"""Update a resource
|
||||
|
||||
:param resource_type: The type of resource to update.
|
||||
@ -563,7 +574,12 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
res = self._get_resource(resource_type, value, **attrs)
|
||||
return res.commit(self, base_path=base_path)
|
||||
|
||||
def _create(self, resource_type: Type[T], base_path=None, **attrs):
|
||||
def _create(
|
||||
self,
|
||||
resource_type: ty.Type[ResourceType],
|
||||
base_path=None,
|
||||
**attrs,
|
||||
) -> ResourceType:
|
||||
"""Create a resource from attributes
|
||||
|
||||
:param resource_type: The type of resource to create.
|
||||
@ -588,8 +604,11 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
return res.create(self, base_path=base_path)
|
||||
|
||||
def _bulk_create(
|
||||
self, resource_type: Type[T], data, base_path=None
|
||||
) -> Generator[T, None, None]:
|
||||
self,
|
||||
resource_type: ty.Type[ResourceType],
|
||||
data,
|
||||
base_path=None,
|
||||
) -> ty.Generator[ResourceType, None, None]:
|
||||
"""Create a resource from attributes
|
||||
|
||||
:param resource_type: The type of resource to create.
|
||||
@ -612,13 +631,13 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
@_check_resource(strict=False)
|
||||
def _get(
|
||||
self,
|
||||
resource_type: Type[T],
|
||||
resource_type: ty.Type[ResourceType],
|
||||
value=None,
|
||||
requires_id=True,
|
||||
base_path=None,
|
||||
skip_cache=False,
|
||||
**attrs,
|
||||
):
|
||||
) -> ResourceType:
|
||||
"""Fetch a resource
|
||||
|
||||
:param resource_type: The type of resource to get.
|
||||
@ -655,12 +674,12 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
|
||||
def _list(
|
||||
self,
|
||||
resource_type: Type[T],
|
||||
resource_type: ty.Type[ResourceType],
|
||||
paginated=True,
|
||||
base_path=None,
|
||||
jmespath_filters=None,
|
||||
**attrs,
|
||||
) -> Generator[T, None, None]:
|
||||
) -> ty.Generator[ResourceType, None, None]:
|
||||
"""List a resource
|
||||
|
||||
:param resource_type: The type of resource to list. This should
|
||||
@ -696,8 +715,12 @@ class Proxy(adapter.Adapter, Generic[T]):
|
||||
return data
|
||||
|
||||
def _head(
|
||||
self, resource_type: Type[T], value=None, base_path=None, **attrs
|
||||
):
|
||||
self,
|
||||
resource_type: ty.Type[ResourceType],
|
||||
value=None,
|
||||
base_path=None,
|
||||
**attrs,
|
||||
) -> ResourceType:
|
||||
"""Retrieve a resource's header
|
||||
|
||||
:param resource_type: The type of resource to retrieve.
|
||||
|
@ -32,10 +32,12 @@ converted into this Resource class' appropriate components and types
|
||||
and then returned to the caller.
|
||||
"""
|
||||
|
||||
import abc
|
||||
import collections
|
||||
import inspect
|
||||
import itertools
|
||||
import operator
|
||||
import typing as ty
|
||||
import urllib.parse
|
||||
import warnings
|
||||
|
||||
@ -93,11 +95,11 @@ def _convert_type(value, data_type, list_type=None):
|
||||
return data_type()
|
||||
|
||||
|
||||
class _BaseComponent:
|
||||
class _BaseComponent(abc.ABC):
|
||||
# The name this component is being tracked as in the Resource
|
||||
key = None
|
||||
key: str
|
||||
# The class to be used for mappings
|
||||
_map_cls = dict
|
||||
_map_cls: ty.Type[ty.Mapping] = dict
|
||||
|
||||
#: Marks the property as deprecated.
|
||||
deprecated = False
|
||||
@ -270,6 +272,8 @@ class Computed(_BaseComponent):
|
||||
class _ComponentManager(collections.abc.MutableMapping):
|
||||
"""Storage of a component type"""
|
||||
|
||||
attributes: ty.Dict[str, ty.Any]
|
||||
|
||||
def __init__(self, attributes=None, synchronized=False):
|
||||
self.attributes = dict() if attributes is None else attributes.copy()
|
||||
self._dirty = set() if synchronized else set(self.attributes.keys())
|
||||
@ -452,14 +456,15 @@ class Resource(dict):
|
||||
# will work properly.
|
||||
|
||||
#: Singular form of key for resource.
|
||||
resource_key = None
|
||||
resource_key: ty.Optional[str] = None
|
||||
#: Plural form of key for resource.
|
||||
resources_key = None
|
||||
resources_key: ty.Optional[str] = None
|
||||
#: Key used for pagination links
|
||||
pagination_key = None
|
||||
|
||||
#: The ID of this resource.
|
||||
id = Body("id")
|
||||
|
||||
#: The name of this resource.
|
||||
name = Body("name")
|
||||
#: The OpenStack location of this resource.
|
||||
@ -469,7 +474,7 @@ class Resource(dict):
|
||||
_query_mapping = QueryParameters()
|
||||
|
||||
#: The base part of the URI for this resource.
|
||||
base_path = ""
|
||||
base_path: str = ""
|
||||
|
||||
#: Allow create operation for this resource.
|
||||
allow_create = False
|
||||
@ -508,22 +513,22 @@ class Resource(dict):
|
||||
create_returns_body = None
|
||||
|
||||
#: Maximum microversion to use for getting/creating/updating the Resource
|
||||
_max_microversion = None
|
||||
_max_microversion: ty.Optional[str] = None
|
||||
#: API microversion (string or None) this Resource was loaded with
|
||||
microversion = None
|
||||
|
||||
_connection = None
|
||||
_body = None
|
||||
_header = None
|
||||
_uri = None
|
||||
_computed = None
|
||||
_original_body = None
|
||||
_body: _ComponentManager
|
||||
_header: _ComponentManager
|
||||
_uri: _ComponentManager
|
||||
_computed: _ComponentManager
|
||||
_original_body: ty.Dict[str, ty.Any] = {}
|
||||
_store_unknown_attrs_as_properties = False
|
||||
_allow_unknown_attrs_in_body = False
|
||||
_unknown_attrs_in_body = None
|
||||
_unknown_attrs_in_body: ty.Dict[str, ty.Any] = {}
|
||||
|
||||
# Placeholder for aliases as dict of {__alias__:__original}
|
||||
_attr_aliases = {}
|
||||
_attr_aliases: ty.Dict[str, str] = {}
|
||||
|
||||
def __init__(self, _synchronized=False, connection=None, **attrs):
|
||||
"""The base resource
|
||||
@ -1072,12 +1077,13 @@ class Resource(dict):
|
||||
:return: A dictionary of key/value pairs where keys are named
|
||||
as they exist as attributes of this class.
|
||||
"""
|
||||
mapping: ty.Union[utils.Munch, ty.Dict]
|
||||
if _to_munch:
|
||||
mapping = utils.Munch()
|
||||
else:
|
||||
mapping = {}
|
||||
|
||||
components = []
|
||||
components: ty.List[ty.Type[_BaseComponent]] = []
|
||||
if body:
|
||||
components.append(Body)
|
||||
if headers:
|
||||
@ -1089,9 +1095,6 @@ class Resource(dict):
|
||||
"At least one of `body`, `headers` or `computed` must be True"
|
||||
)
|
||||
|
||||
# isinstance stricly requires this to be a tuple
|
||||
components = tuple(components)
|
||||
|
||||
if body and self._allow_unknown_attrs_in_body:
|
||||
for key in self._unknown_attrs_in_body:
|
||||
converted = self._attr_to_dict(
|
||||
@ -1105,7 +1108,8 @@ class Resource(dict):
|
||||
# but is slightly different in that we're looking at an instance
|
||||
# and we're mapping names on this class to their actual stored
|
||||
# values.
|
||||
for attr, component in self._attributes_iterator(components):
|
||||
# NOTE: isinstance stricly requires components to be a tuple
|
||||
for attr, component in self._attributes_iterator(tuple(components)):
|
||||
if original_names:
|
||||
key = component.name
|
||||
else:
|
||||
@ -1167,6 +1171,7 @@ class Resource(dict):
|
||||
*,
|
||||
resource_request_key=None,
|
||||
):
|
||||
body: ty.Union[ty.Dict[str, ty.Any], ty.List[ty.Any]]
|
||||
if patch:
|
||||
if not self._store_unknown_attrs_as_properties:
|
||||
# Default case
|
||||
@ -1592,7 +1597,7 @@ class Resource(dict):
|
||||
"Invalid create method: %s" % cls.create_method
|
||||
)
|
||||
|
||||
body = []
|
||||
_body: ty.List[ty.Any] = []
|
||||
resources = []
|
||||
for attrs in data:
|
||||
# NOTE(gryf): we need to create resource objects, since
|
||||
@ -1605,9 +1610,12 @@ class Resource(dict):
|
||||
request = resource._prepare_request(
|
||||
requires_id=requires_id, base_path=base_path
|
||||
)
|
||||
body.append(request.body)
|
||||
_body.append(request.body)
|
||||
|
||||
body: ty.Union[ty.Dict[str, ty.Any], ty.List[ty.Any]] = _body
|
||||
|
||||
if prepend_key:
|
||||
assert cls.resources_key
|
||||
body = {cls.resources_key: body}
|
||||
|
||||
response = method(
|
||||
|
@ -11,6 +11,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import typing as ty
|
||||
import warnings
|
||||
|
||||
import os_service_types
|
||||
@ -44,11 +45,11 @@ class _ServiceDisabledProxyShim:
|
||||
|
||||
class ServiceDescription:
|
||||
#: Dictionary of supported versions and proxy classes for that version
|
||||
supported_versions = None
|
||||
supported_versions: ty.Dict[str, ty.Type[proxy_mod.Proxy]] = {}
|
||||
#: main service_type to use to find this service in the catalog
|
||||
service_type = None
|
||||
service_type: str
|
||||
#: list of aliases this service might be registered as
|
||||
aliases = []
|
||||
aliases: ty.List[str] = []
|
||||
|
||||
def __init__(self, service_type, supported_versions=None, aliases=None):
|
||||
"""Class describing how to interact with a REST service.
|
||||
|
@ -67,7 +67,7 @@ def generate_fake_resource(
|
||||
:raises NotImplementedError: If a resource attribute specifies a ``type``
|
||||
or ``list_type`` that cannot be automatically generated
|
||||
"""
|
||||
base_attrs = dict()
|
||||
base_attrs: Dict[str, Any] = {}
|
||||
for name, value in inspect.getmembers(
|
||||
resource_type,
|
||||
predicate=lambda x: isinstance(x, (resource.Body, resource.URI)),
|
||||
@ -182,7 +182,7 @@ def generate_fake_resources(
|
||||
# (better) type annotations
|
||||
def generate_fake_proxy(
|
||||
service: Type[service_description.ServiceDescription],
|
||||
api_version: Optional[int] = None,
|
||||
api_version: Optional[str] = None,
|
||||
) -> proxy.Proxy:
|
||||
"""Generate a fake proxy for the given service type
|
||||
|
||||
@ -246,10 +246,10 @@ def generate_fake_proxy(
|
||||
)
|
||||
else:
|
||||
api_version = list(supported_versions)[0]
|
||||
elif str(api_version) not in supported_versions:
|
||||
elif api_version not in supported_versions:
|
||||
raise ValueError(
|
||||
f"API version {api_version} is not supported by openstacksdk. "
|
||||
f"Supported API versions are: {', '.join(supported_versions)}"
|
||||
)
|
||||
|
||||
return mock.create_autospec(supported_versions[str(api_version)])
|
||||
return mock.create_autospec(supported_versions[api_version])
|
||||
|
@ -13,11 +13,12 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from io import StringIO
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import pprint
|
||||
import sys
|
||||
import typing as ty
|
||||
|
||||
import fixtures
|
||||
from oslotest import base
|
||||
@ -59,8 +60,10 @@ class TestCase(base.BaseTestCase):
|
||||
|
||||
self.warnings = self.useFixture(os_fixtures.WarningsFixture())
|
||||
|
||||
self._log_stream: ty.TextIO
|
||||
|
||||
if os.environ.get('OS_LOG_CAPTURE') in _TRUE_VALUES:
|
||||
self._log_stream = StringIO()
|
||||
self._log_stream = io.StringIO()
|
||||
if os.environ.get('OS_ALWAYS_LOG') in _TRUE_VALUES:
|
||||
self.addCleanup(self.printLogs)
|
||||
else:
|
||||
|
@ -16,6 +16,7 @@ import queue
|
||||
import string
|
||||
import threading
|
||||
import time
|
||||
import typing as ty
|
||||
|
||||
import keystoneauth1
|
||||
from keystoneauth1 import adapter as ks_adapter
|
||||
@ -417,7 +418,7 @@ class TinyDAG:
|
||||
def _start_traverse(self):
|
||||
"""Initialize graph traversing"""
|
||||
self._run_in_degree = self._get_in_degree()
|
||||
self._queue = queue.Queue()
|
||||
self._queue: queue.Queue[str] = queue.Queue()
|
||||
self._done = set()
|
||||
self._it_cnt = len(self._graph)
|
||||
|
||||
@ -427,8 +428,7 @@ class TinyDAG:
|
||||
|
||||
def _get_in_degree(self):
|
||||
"""Calculate the in_degree (count incoming) for nodes"""
|
||||
_in_degree = dict()
|
||||
_in_degree = {u: 0 for u in self._graph.keys()}
|
||||
_in_degree: ty.Dict[str, int] = {u: 0 for u in self._graph.keys()}
|
||||
for u in self._graph:
|
||||
for v in self._graph[u]:
|
||||
_in_degree[v] += 1
|
||||
@ -568,7 +568,7 @@ class Munch(dict):
|
||||
def munchify(x, factory=Munch):
|
||||
"""Recursively transforms a dictionary into a Munch via copy."""
|
||||
# Munchify x, using `seen` to track object cycles
|
||||
seen = dict()
|
||||
seen: ty.Dict[int, ty.Any] = dict()
|
||||
|
||||
def munchify_cycles(obj):
|
||||
try:
|
||||
@ -608,7 +608,7 @@ def unmunchify(x):
|
||||
"""Recursively converts a Munch into a dictionary."""
|
||||
|
||||
# Munchify x, using `seen` to track object cycles
|
||||
seen = dict()
|
||||
seen: ty.Dict[int, ty.Any] = dict()
|
||||
|
||||
def unmunchify_cycles(obj):
|
||||
try:
|
||||
|
Loading…
Reference in New Issue
Block a user