From f18342b75853e345c10119ab0e7da612779bbcc5 Mon Sep 17 00:00:00 2001 From: Yu-Ting Hsiung Date: Sat, 31 May 2025 23:30:27 +0800 Subject: [PATCH] refactor(questions): type questions with TypedDict --- commitizen/commands/commit.py | 2 +- commitizen/cz/base.py | 4 +-- .../conventional_commits.py | 6 ++-- commitizen/cz/customize/customize.py | 7 ++-- commitizen/cz/jira/jira.py | 4 +-- commitizen/defaults.py | 6 ++-- commitizen/question.py | 32 +++++++++++++++++++ tests/conftest.py | 3 +- 8 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 commitizen/question.py diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 43feb272b..4c9972a99 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -66,7 +66,7 @@ def _prompt_commit_questions(self) -> str: # Prompt user for the commit message cz = self.cz questions = cz.questions() - for question in filter(lambda q: q["type"] == "list", questions): + for question in (q for q in questions if q["type"] == "list"): question["use_shortcuts"] = self.config.settings["use_shortcuts"] try: answers = questionary.prompt(questions, style=cz.style) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 9e803c3d0..a30540cae 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -9,7 +9,7 @@ from commitizen import git from commitizen.config.base_config import BaseConfig -from commitizen.defaults import Questions +from commitizen.question import CzQuestion class MessageBuilderHook(Protocol): @@ -68,7 +68,7 @@ def __init__(self, config: BaseConfig) -> None: self.config.settings.update({"style": BaseCommitizen.default_style_config}) @abstractmethod - def questions(self) -> Questions: + def questions(self) -> Iterable[CzQuestion]: """Questions regarding the commit message.""" @abstractmethod diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 912770a72..ca4809a90 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -3,7 +3,7 @@ from commitizen import defaults from commitizen.cz.base import BaseCommitizen from commitizen.cz.utils import multiple_line_breaker, required_validator -from commitizen.defaults import Questions +from commitizen.question import CzQuestion __all__ = ["ConventionalCommitsCz"] @@ -29,7 +29,7 @@ class ConventionalCommitsCz(BaseCommitizen): } changelog_pattern = defaults.BUMP_PATTERN - def questions(self) -> Questions: + def questions(self) -> list[CzQuestion]: return [ { "type": "list", @@ -122,8 +122,8 @@ def questions(self) -> Questions: }, { "type": "confirm", - "message": "Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer", "name": "is_breaking_change", + "message": "Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer", "default": False, }, { diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 8f844501e..6581ad444 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -2,6 +2,8 @@ from typing import TYPE_CHECKING +from commitizen.question import CzQuestion + if TYPE_CHECKING: from jinja2 import Template else: @@ -14,7 +16,6 @@ from commitizen import defaults from commitizen.config import BaseConfig from commitizen.cz.base import BaseCommitizen -from commitizen.defaults import Questions from commitizen.exceptions import MissingCzCustomizeConfigError __all__ = ["CustomizeCommitsCz"] @@ -45,8 +46,8 @@ def __init__(self, config: BaseConfig) -> None: if value := self.custom_settings.get(attr_name): setattr(self, attr_name, value) - def questions(self) -> Questions: - return self.custom_settings.get("questions", [{}]) + def questions(self) -> list[CzQuestion]: + return self.custom_settings.get("questions", [{}]) # type: ignore def message(self, answers: dict) -> str: message_template = Template(self.custom_settings.get("message_template", "")) diff --git a/commitizen/cz/jira/jira.py b/commitizen/cz/jira/jira.py index 05e23e169..eafded615 100644 --- a/commitizen/cz/jira/jira.py +++ b/commitizen/cz/jira/jira.py @@ -1,13 +1,13 @@ import os from commitizen.cz.base import BaseCommitizen -from commitizen.defaults import Questions +from commitizen.question import CzQuestion __all__ = ["JiraSmartCz"] class JiraSmartCz(BaseCommitizen): - def questions(self) -> Questions: + def questions(self) -> list[CzQuestion]: return [ { "type": "input", diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 7a51389b7..a49d6d942 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -6,8 +6,10 @@ from collections.abc import Iterable, MutableMapping, Sequence from typing import Any, TypedDict +from commitizen.question import CzQuestion + # Type -Questions = Iterable[MutableMapping[str, Any]] +Questions = Iterable[MutableMapping[str, Any]] # TODO: deprecate this? class CzSettings(TypedDict, total=False): @@ -16,7 +18,7 @@ class CzSettings(TypedDict, total=False): bump_map_major_version_zero: OrderedDict[str, str] change_type_order: list[str] - questions: Questions + questions: Iterable[CzQuestion] example: str | None schema_pattern: str | None schema: str | None diff --git a/commitizen/question.py b/commitizen/question.py new file mode 100644 index 000000000..393e38609 --- /dev/null +++ b/commitizen/question.py @@ -0,0 +1,32 @@ +from typing import Callable, Literal, TypedDict, Union + + +class Choice(TypedDict, total=False): + value: str + name: str + key: str + + +class ListQuestion(TypedDict, total=False): + type: Literal["list"] + name: str + message: str + choices: list[Choice] + use_shortcuts: bool + + +class InputQuestion(TypedDict, total=False): + type: Literal["input"] + name: str + message: str + filter: Callable[[str], str] + + +class ConfirmQuestion(TypedDict): + type: Literal["confirm"] + name: str + message: str + default: bool + + +CzQuestion = Union[ListQuestion, InputQuestion, ConfirmQuestion] diff --git a/tests/conftest.py b/tests/conftest.py index 1b49dcbfa..a4815b3d5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,6 +17,7 @@ from commitizen.config import BaseConfig from commitizen.cz import registry from commitizen.cz.base import BaseCommitizen +from commitizen.question import CzQuestion from tests.utils import create_file_and_commit SIGNER = "GitHub Action" @@ -222,7 +223,7 @@ def use_cz_semver(mocker): class MockPlugin(BaseCommitizen): - def questions(self) -> defaults.Questions: + def questions(self) -> list[CzQuestion]: return [] def message(self, answers: dict) -> str: