From: Sebastian Wagner Date: Mon, 1 Feb 2021 15:13:19 +0000 (+0100) Subject: python-common: Type annotation for ServiceSpec.from_json X-Git-Tag: v17.1.0~3068^2~2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=7a297262aa1ec080f2264f5b16747cdd740d446d;p=ceph.git python-common: Type annotation for ServiceSpec.from_json Signed-off-by: Sebastian Wagner --- diff --git a/src/pybind/mgr/cephadm/module.py b/src/pybind/mgr/cephadm/module.py index a6ffdb4a037be..7034336b5c13e 100644 --- a/src/pybind/mgr/cephadm/module.py +++ b/src/pybind/mgr/cephadm/module.py @@ -12,7 +12,7 @@ from threading import Event import string from typing import List, Dict, Optional, Callable, Tuple, TypeVar, \ - Any, Set, TYPE_CHECKING, cast, Iterator, NamedTuple + Any, Set, TYPE_CHECKING, cast, Iterator, NamedTuple, Sequence import datetime import os @@ -2003,7 +2003,7 @@ class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule, } @trivial_completion - def plan(self, specs: List[GenericSpec]) -> List: + def plan(self, specs: Sequence[GenericSpec]) -> List: results = [{'warning': 'WARNING! Dry-Runs are snapshots of a certain point in time and are bound \n' 'to the current inventory setup. If any on these conditions changes, the \n' 'preview will be invalid. Please make sure to have a minimal \n' @@ -2054,7 +2054,7 @@ class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule, return "Scheduled %s update..." % spec.service_name() @trivial_completion - def apply(self, specs: List[GenericSpec]) -> List[str]: + def apply(self, specs: Sequence[GenericSpec]) -> List[str]: results = [] for spec in specs: results.append(self._apply(spec)) diff --git a/src/pybind/mgr/orchestrator/_interface.py b/src/pybind/mgr/orchestrator/_interface.py index 6034e219daf0b..1a247a5dce258 100644 --- a/src/pybind/mgr/orchestrator/_interface.py +++ b/src/pybind/mgr/orchestrator/_interface.py @@ -882,7 +882,7 @@ class Orchestrator(object): """ raise NotImplementedError() - def apply(self, specs: List["GenericSpec"]) -> Completion[List[str]]: + def apply(self, specs: Sequence["GenericSpec"]) -> Completion[List[str]]: """ Applies any spec """ @@ -921,7 +921,7 @@ class Orchestrator(object): completion = completion.then(next) return completion - def plan(self, spec: List["GenericSpec"]) -> Completion[List]: + def plan(self, spec: Sequence["GenericSpec"]) -> Completion[List]: """ Plan (Dry-run, Preview) a List of Specs. """ diff --git a/src/pybind/mgr/orchestrator/module.py b/src/pybind/mgr/orchestrator/module.py index 534da49bde458..1ed7124068e76 100644 --- a/src/pybind/mgr/orchestrator/module.py +++ b/src/pybind/mgr/orchestrator/module.py @@ -883,9 +883,10 @@ Usage: raise OrchestratorValidationError(usage) spec = ServiceSpec.from_json(yaml.safe_load(inbuf)) else: - spec = PlacementSpec.from_string(placement) - assert daemon_type - spec = ServiceSpec(daemon_type.value, placement=spec) + if not placement or not daemon_type: + raise OrchestratorValidationError(usage) + placement_spec = PlacementSpec.from_string(placement) + spec = ServiceSpec(daemon_type.value, placement=placement_spec) if daemon_type == ServiceType.mon: completion = self.add_mon(spec) @@ -906,11 +907,11 @@ Usage: elif daemon_type == ServiceType.mds: completion = self.add_mds(spec) elif daemon_type == ServiceType.rgw: - completion = self.add_rgw(spec) + completion = self.add_rgw(cast(RGWSpec, spec)) elif daemon_type == ServiceType.nfs: - completion = self.add_nfs(spec) + completion = self.add_nfs(cast(NFSServiceSpec, spec)) elif daemon_type == ServiceType.iscsi: - completion = self.add_iscsi(spec) + completion = self.add_iscsi(cast(IscsiServiceSpec, spec)) elif daemon_type == ServiceType.cephadm_exporter: completion = self.add_cephadm_exporter(spec) else: diff --git a/src/python-common/ceph/deployment/service_spec.py b/src/python-common/ceph/deployment/service_spec.py index 6602c10f9ddda..f10823a78c35f 100644 --- a/src/python-common/ceph/deployment/service_spec.py +++ b/src/python-common/ceph/deployment/service_spec.py @@ -3,13 +3,16 @@ import fnmatch import re from collections import namedtuple, OrderedDict from functools import wraps -from typing import Optional, Dict, Any, List, Union, Callable, Iterable +from typing import Optional, Dict, Any, List, Union, Callable, Iterable, Type, TypeVar, cast import yaml from ceph.deployment.hostspec import HostSpec from ceph.deployment.utils import unwrap_ipv6 +ServiceSpecT = TypeVar('ServiceSpecT', bound='ServiceSpec') +FuncT = TypeVar('FuncT', bound=Callable) + class ServiceSpecValidationError(Exception): """ @@ -35,7 +38,7 @@ def assert_valid_host(name): raise ServiceSpecValidationError(e) -def handle_type_error(method): +def handle_type_error(method: FuncT) -> FuncT: @wraps(method) def inner(cls, *args, **kwargs): try: @@ -43,7 +46,7 @@ def handle_type_error(method): except (TypeError, AttributeError) as e: error_msg = '{}: {}'.format(cls.__name__, e) raise ServiceSpecValidationError(error_msg) - return inner + return cast(FuncT, inner) class HostPlacementSpec(namedtuple('HostPlacementSpec', ['hostname', 'network', 'name'])): @@ -436,11 +439,7 @@ class ServiceSpec(object): @classmethod @handle_type_error - def from_json(cls, json_spec): - # type: (dict) -> Any - # Python 3: - # >>> ServiceSpecs = TypeVar('Base', bound=ServiceSpec) - # then, the real type is: (dict) -> ServiceSpecs + def from_json(cls: Type[ServiceSpecT], json_spec: Dict) -> ServiceSpecT: """ Initialize 'ServiceSpec' object data from a json structure