Merge "Add typing"

This commit is contained in:
Zuul
2025-12-05 16:47:43 +00:00
committed by Gerrit Code Review
8 changed files with 97 additions and 36 deletions

View File

@@ -13,7 +13,7 @@ repos:
- id: check-yaml
files: .*\.(yaml|yml)$
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.7
rev: v0.14.8
hooks:
- id: ruff-check
args: ['--fix', '--unsafe-fixes']

View File

@@ -30,5 +30,5 @@ _C = _translators.contextual_form
_P = _translators.plural_form
def get_available_languages():
def get_available_languages() -> list[str]:
return oslo_i18n.get_available_languages(DOMAIN)

View File

@@ -10,7 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_policy import opts as policy_opts
from oslo_config import cfg # type: ignore
from oslo_policy import opts as policy_opts # type: ignore
from oslo_utils import fileutils
from oslo_upgradecheck import upgradecheck
@@ -20,7 +21,9 @@ Common checks which can be used by multiple services.
"""
def check_policy_json(self, conf):
def check_policy_json(
self: upgradecheck.UpgradeCommands, conf: cfg.ConfigOpts
) -> upgradecheck.Result:
"Checks to see if policy file is JSON-formatted policy file."
# NOTE(gmann): This method need [oslo_policy].policy_file

View File

@@ -15,11 +15,11 @@ import os.path
import tempfile
import yaml
from oslo_config import cfg
from oslo_config import cfg # type: ignore
from oslo_config import fixture as config
from oslo_policy import opts as policy_opts
from oslo_serialization import jsonutils
from oslotest import base
from oslo_policy import opts as policy_opts # type: ignore
from oslo_serialization import jsonutils # type: ignore
from oslotest import base # type: ignore
from oslo_upgradecheck import common_checks
from oslo_upgradecheck import upgradecheck

View File

@@ -22,8 +22,8 @@ import subprocess
import sys
from unittest import mock
from oslo_config import cfg
from oslotest import base
from oslo_config import cfg # type: ignore
from oslotest import base # type: ignore
from oslo_upgradecheck import upgradecheck
@@ -54,8 +54,13 @@ class TestCommands(upgradecheck.UpgradeCommands):
)
class SuccessCommands(TestCommands):
_upgrade_checks = ()
class SuccessCommands(upgradecheck.UpgradeCommands):
def success(self):
return upgradecheck.Result(
upgradecheck.Code.SUCCESS, 'Always succeeds'
)
_upgrade_checks = (('always succeeds', success),)
class TestUpgradeCommands(base.BaseTestCase):

View File

@@ -13,18 +13,20 @@
# License for the specific language governing permissions and limitations
# under the License.
from collections.abc import Callable, Iterable
import json
import sys
import textwrap
import traceback
from typing import Any, TypedDict
import enum
from oslo_config import cfg
from oslo_config import cfg # type: ignore
import prettytable
from oslo_upgradecheck._i18n import _
CONF = None
CONF: cfg.ConfigOpts | None = None
class Code(enum.IntEnum):
@@ -59,12 +61,23 @@ class Result:
information on what issue was discovered along with any remediation.
"""
def __init__(self, code, details=None):
def __init__(self, code: Code, details: str | None = None) -> None:
super().__init__()
self.code = code
self.details = details
class _OutputCheck(TypedDict):
check: str
result: Code
details: str | None
class _Output(TypedDict):
name: str
checks: list[_OutputCheck]
class UpgradeCommands:
"""Base class for upgrade checks
@@ -79,18 +92,27 @@ class UpgradeCommands:
"""
display_title = _('Upgrade Check Results')
_upgrade_checks = ()
_upgrade_checks: tuple[
tuple[
str,
Callable[..., Result]
| tuple[Callable[..., Result], dict[str, Any]],
],
...,
] = ()
def _get_details(self, upgrade_check_result):
if upgrade_check_result.details is not None:
# wrap the text on the details to 60 characters
return '\n'.join(
textwrap.wrap(
upgrade_check_result.details, 60, subsequent_indent=' '
)
def _get_details(self, upgrade_check_result: Result) -> str | None:
if upgrade_check_result.details is None:
return None
# wrap the text on the details to 60 characters
return '\n'.join(
textwrap.wrap(
upgrade_check_result.details, 60, subsequent_indent=' '
)
)
def check(self):
def check(self) -> Code:
"""Performs checks to see if the deployment is ready for upgrade.
These checks are expected to be run BEFORE services are restarted with
@@ -130,14 +152,15 @@ class UpgradeCommands:
# Since registering opts can be overridden by consuming code, we can't
# assume that our locally defined option exists.
if (
hasattr(CONF, 'command')
CONF is not None
and hasattr(CONF, 'command')
and hasattr(CONF.command, 'json')
and CONF.command.json
):
# NOTE(bnemec): We use str on the translated string to
# force immediate translation if lazy translation is in use.
# See lp1801761 for details.
output = {'name': str(self.display_title), 'checks': []}
output: _Output = {'name': str(self.display_title), 'checks': []}
for name, result in check_results:
output['checks'].append(
{
@@ -169,7 +192,9 @@ class UpgradeCommands:
return return_code
def register_cli_options(conf, upgrade_command):
def register_cli_options(
conf: cfg.ConfigOpts, upgrade_command: UpgradeCommands
) -> None:
"""Set up the command line options.
Adds a subcommand to support 'upgrade check' on the command line.
@@ -179,7 +204,7 @@ def register_cli_options(conf, upgrade_command):
:param upgrade_command: The UpgradeCommands instance.
"""
def add_parsers(subparsers):
def add_parsers(subparsers: Any) -> None:
upgrade_action = subparsers.add_parser('upgrade')
upgrade_action.add_argument('check')
upgrade_action.set_defaults(action_fn=upgrade_command.check)
@@ -194,14 +219,14 @@ def register_cli_options(conf, upgrade_command):
conf.register_cli_opt(opt)
def run(conf):
def run(conf: cfg.ConfigOpts) -> int:
"""Run the requested command.
:param conf: An oslo.confg ConfigOpts instance on which the upgrade
commands have been previously registered.
"""
try:
return conf.command.action_fn()
return conf.command.action_fn() # type: ignore
except Exception:
print(_('Error:\n%s') % traceback.format_exc())
# This is 255 so it's not confused with the upgrade check exit codes.
@@ -209,12 +234,12 @@ def run(conf):
def main(
conf,
project,
upgrade_command,
argv=sys.argv[1:],
default_config_files=None,
):
conf: cfg.ConfigOpts,
project: str,
upgrade_command: UpgradeCommands,
argv: list[str] = sys.argv[1:],
default_config_files: Iterable[str] | None = None,
) -> int:
"""Simple implementation of main for upgrade checks
This can be used in upgrade check commands to provide the minimum

View File

@@ -35,6 +35,20 @@ packages = [
"oslo_upgradecheck"
]
[tool.mypy]
python_version = "3.10"
show_column_numbers = true
show_error_context = true
strict = true
exclude = '(?x)(doc | examples | releasenotes)'
[[tool.mypy.overrides]]
module = ["oslo_upgradecheck.tests.*"]
disallow_untyped_calls = false
disallow_untyped_defs = false
disallow_subclassing_any = false
disallow_any_generics = false
[tool.ruff]
line-length = 79

14
tox.ini
View File

@@ -15,11 +15,25 @@ deps =
commands = stestr run --slowest {posargs}
[testenv:pep8]
description =
Run style checks.
skip_install = true
deps =
pre-commit
{[testenv:mypy]deps}
commands =
pre-commit run -a
{[testenv:mypy]commands}
[testenv:mypy]
description =
Run type checks.
deps =
{[testenv]deps}
mypy
types-PyYAML
commands =
mypy --cache-dir="{envdir}/mypy_cache" {posargs:oslo_upgradecheck}
[testenv:venv]
commands = {posargs}