Fix mypy type checking errors

The typed oslo.config stubs introduced new type mismatches that
needed attention across five files.

An empty set() without annotation left mypy unable to infer the
element type, so _DEPRECATED_EXCEPTIONS now carries an explicit
set[type] annotation.

The list_opts() concatenation mixed list[BoolOpt] with list[Opt]
via the + operator, which mypy rejects because list is invariant.
Switching to unpacking ([*a, *b, ...]) builds a single list whose
element type is the union of all sources, sidestepping the issue
without casts or redundant annotations on each individual list.

_store_global_conf was annotated as returning ConfigOpts but never
returns anything — the return type is now None to match reality.

The tuple-based membership checks in _mutate_hook ((None, 'debug')
in fresh) are a legitimate oslo.config API pattern for querying
mutated options by (group, name), but the typed stubs only declare
__contains__(str). These are silenced with type: ignore until the
stubs are updated upstream.

The TestConfigOpts.__call__ override intentionally narrows the
parent signature to hardcode test defaults — this is a deliberate
simplification for test ergonomics, not a Liskov violation worth
fixing, so it gets a type: ignore[override].

Assisted-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Change-Id: I24a98cb4f58b5452a8510b8c756ad6f257e2bb0a
Signed-off-by: Hervé Beraud <herveberaud.pro@gmail.com>
This commit is contained in:
Hervé Beraud
2026-05-26 10:26:23 +02:00
parent 546add476e
commit 0640ed88fe
5 changed files with 12 additions and 12 deletions
+7 -7
View File
@@ -275,12 +275,12 @@ def list_opts() -> list[tuple[str | None, list[cfg.Opt]]]:
return [
(
None,
(
common_cli_opts
+ logging_cli_opts
+ generic_log_opts
+ log_opts
+ versionutils.deprecated_opts
),
[
*common_cli_opts,
*logging_cli_opts,
*generic_log_opts,
*log_opts,
*versionutils.deprecated_opts,
],
)
]
+1 -1
View File
@@ -55,7 +55,7 @@ def _dictify_context(
_CONF = None
def _store_global_conf(conf: cfg.ConfigOpts) -> cfg.ConfigOpts:
def _store_global_conf(conf: cfg.ConfigOpts) -> None:
global _CONF
_CONF = conf
+2 -2
View File
@@ -272,10 +272,10 @@ def _load_log_config(log_config_append: str) -> None:
def _mutate_hook(conf: cfg.ConfigOpts, fresh: cfg.ConfigOpts) -> None:
"""Reconfigures oslo.log according to the mutated options."""
if (None, 'debug') in fresh:
if (None, 'debug') in fresh: # type: ignore[comparison-overlap]
_refresh_root_level(conf.debug)
if (None, 'log-config-append') in fresh:
if (None, 'log-config-append') in fresh: # type: ignore[comparison-overlap]
setattr(_load_log_config, 'old_time', 0)
if conf.log_config_append:
+1 -1
View File
@@ -1340,7 +1340,7 @@ class DomainTestCase(LogTestBase):
class SetDefaultsTestCase(BaseTestCase):
class TestConfigOpts(cfg.ConfigOpts):
def __call__(self, args=None):
def __call__(self, args=None): # type: ignore[override]
return cfg.ConfigOpts.__call__(
self,
args=args,
+1 -1
View File
@@ -33,7 +33,7 @@ _C = TypeVar('_C', bound=type[Any])
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
_DEPRECATED_EXCEPTIONS = set()
_DEPRECATED_EXCEPTIONS: set[type] = set()
deprecated_opts = [