diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 88f6566fb1..6fc9dc0693 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: - "jinja2>=2.11.3" # 3.1.2 / 3.1.2 - "packaging>=20" # 20 seems to be available with RHEL8 - "pint>=0.16.1" # 0.16.1 - - "pydantic>=1.10, <2.0" + - "pydantic>=2.8" - "pygments>=2.7.4" # 2.7.4 is the current one available for RHEL9 - "requests>=2.25.1" # 2.28.2 / 2.31.0 - "ruamel.yaml>=0.16.6" # 0.17.32 / 0.17.32 @@ -87,7 +87,7 @@ repos: - "jinja2>=2.11.3" # 3.1.2 / 3.1.2 - "packaging>=20" # 20 seems to be available with RHEL8 - "pint>=0.16.1" # 0.16.1 / 0.19.x TODO: Pint 0.20 requires larger changes to tmt.hardware - - "pydantic>=1.10, <2.0" + - "pydantic>=2.8" - "pygments>=2.7.4" # 2.7.4 is the current one available for RHEL9 - "requests>=2.25.1" # 2.28.2 / 2.31.0 - "ruamel.yaml>=0.16.6" # 0.17.32 / 0.17.32 @@ -160,7 +160,7 @@ repos: - "docutils>=0.16" # 0.16 is the current one available for RHEL9 - "packaging>=20" # 20 seems to be available with RHEL8 - "pint<0.20" - - "pydantic>=1.10, <2.0" + - "pydantic>=2.8" - "pygments>=2.7.4" # 2.7.4 is the current one available for RHEL9 # Help installation by reducing the set of inspected botocore release. # There is *a lot* of them, and hatch might fetch many of them. diff --git a/pyproject.toml b/pyproject.toml index 380b6bf946..6a548c1886 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ dependencies = [ # F39 / PyPI "jinja2>=2.11.3", # 3.1.2 / 3.1.2 "packaging>=20", # 20 seems to be available with RHEL8 "pint>=0.16.1", # 0.16.1 - "pydantic>=1.10, <2.0", + "pydantic>=2.8", "pygments>=2.7.4", # 2.7.4 is the current one available for RHEL9 "requests>=2.25.1", # 2.28.2 / 2.31.0 "ruamel.yaml>=0.16.6", # 0.17.32 / 0.17.32 @@ -417,6 +417,9 @@ builtins-ignorelist = ["help", "format", "input", "filter", "copyright", "max"] # Banning builtins is not yet supported: https://github.com/astral-sh/ruff/issues/10079 # "builtins.open".msg = "Use Path.{write_text,append_text,read_text,write_bytes,read_bytes} instead." +[tool.ruff.lint.flake8-type-checking] +runtime-evaluated-base-classes = ["pydantic.BaseModel"] + [tool.ruff.lint.isort] known-first-party = ["tmt"] diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 73229f6752..87031666cb 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -8,6 +8,7 @@ import fmf import pytest +from pydantic import HttpUrl import tmt.config from tmt.utils import Path @@ -89,12 +90,12 @@ def test_link_config_invalid(config_path: Path): cause = str(error.value.__cause__) assert '6 validation errors for LinkConfig' in cause - assert re.search(r'type\s*value is not a valid enumeration member', cause) - assert re.search(r'url\s*invalid or missing URL scheme', cause) - assert re.search(r'tmt-web-url\s*URL host invalid', cause) - assert re.search(r'unknown\s*extra fields not permitted', cause) - assert re.search(r'token\s*field required', cause) - assert re.search(r'additional_key\s*extra fields not permitted', cause) + assert re.search(r"type\s*Input should be 'jira'", cause) + assert re.search(r"url\s*Input should be a valid URL", cause) + assert re.search(r"tmt-web-url\s*Input should be a valid URL", cause) + assert re.search(r"token\s*Field required", cause) + assert re.search(r"unknown\s*Extra inputs are not permitted", cause) + assert re.search(r"additional_key\s*Extra inputs are not permitted", cause) def test_link_config_valid(config_path: Path): @@ -111,8 +112,8 @@ def test_link_config_valid(config_path: Path): link = tmt.config.Config().link assert link.issue_tracker[0].type == 'jira' - assert link.issue_tracker[0].url == 'https://issues.redhat.com' - assert link.issue_tracker[0].tmt_web_url == 'https://tmt-web-url.com' + assert link.issue_tracker[0].url == HttpUrl('https://issues.redhat.com') + assert link.issue_tracker[0].tmt_web_url == HttpUrl('https://tmt-web-url.com') assert link.issue_tracker[0].token == 'secret' @@ -131,4 +132,4 @@ def test_link_config_empty(config_path: Path): cause = str(error.value.__cause__) assert '1 validation error for LinkConfig' in cause - assert re.search(r'issue-tracker\s*field required', cause) + assert re.search(r'issue-tracker\s*Field required', cause) diff --git a/tmt/config/__init__.py b/tmt/config/__init__.py index adbff3d4c1..306f481941 100644 --- a/tmt/config/__init__.py +++ b/tmt/config/__init__.py @@ -85,7 +85,7 @@ def link(self) -> Optional[LinkConfig]: if not link_config: return None try: - return LinkConfig.parse_obj(link_config.data) + return LinkConfig.model_validate(link_config.data) except ValidationError as error: raise tmt.utils.SpecificationError( f"Invalid link configuration in '{link_config.name}'.") from error diff --git a/tmt/config/models/__init__.py b/tmt/config/models/__init__.py index a7dbb88727..1622936666 100644 --- a/tmt/config/models/__init__.py +++ b/tmt/config/models/__init__.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Extra +from pydantic import BaseModel, ConfigDict def create_alias(name: str) -> str: @@ -6,8 +6,9 @@ def create_alias(name: str) -> str: class BaseConfig(BaseModel): - class Config: + model_config = ConfigDict( # Accept only keys with dashes instead of underscores - alias_generator = create_alias - extra = Extra.forbid - validate_assignment = True + alias_generator=create_alias, + extra='forbid', + validate_assignment=True + ) diff --git a/tmt/utils/jira.py b/tmt/utils/jira.py index b657934f53..13df0aa457 100644 --- a/tmt/utils/jira.py +++ b/tmt/utils/jira.py @@ -89,7 +89,7 @@ def from_issue_url( continue # Issue url must match - if issue_url.startswith(issue_tracker.url): + if issue_url.startswith(str(issue_tracker.url)): return JiraInstance(issue_tracker, logger=logger) return None