diff --git a/craft_archives/repo/apt_ppa.py b/craft_archives/repo/apt_ppa.py index 4aba4ac..138b0c7 100644 --- a/craft_archives/repo/apt_ppa.py +++ b/craft_archives/repo/apt_ppa.py @@ -17,9 +17,11 @@ """Personal Package Archive helpers.""" # pyright: reportMissingTypeStubs=false +# Eliminate launchpadlib typing issues: +# pyright: reportUnknownMemberType=false import logging -from typing import Tuple +from typing import Tuple, cast import lazr.restfulclient.errors # type: ignore from launchpadlib.launchpad import Launchpad # type: ignore @@ -39,14 +41,13 @@ def split_ppa_parts(*, ppa: str) -> Tuple[str, str]: def get_launchpad_ppa_key_id(*, ppa: str) -> str: """Query Launchpad for PPA's key ID.""" - # pyright: reportUnknownMemberType=false, reportUnknownVariableType=false owner, name = split_ppa_parts(ppa=ppa) launchpad = Launchpad.login_anonymously("snapcraft", "production") launchpad_url = f"~{owner}/+archive/{name}" logger.debug(f"Loading launchpad url: {launchpad_url}") try: - key_id: str = launchpad.load(launchpad_url).signing_key_fingerprint + key_id: str = cast(str, launchpad.load(launchpad_url).signing_key_fingerprint) except lazr.restfulclient.errors.NotFound as error: raise errors.AptPPAInstallError(ppa, "not found on launchpad") from error diff --git a/craft_archives/repo/package_repository.py b/craft_archives/repo/package_repository.py index bff8fc8..56acbbb 100644 --- a/craft_archives/repo/package_repository.py +++ b/craft_archives/repo/package_repository.py @@ -23,8 +23,13 @@ from urllib.parse import urlparse import pydantic -from overrides import overrides # pyright: reportUnknownVariableType=false -from pydantic import AnyUrl, ConstrainedStr, root_validator, validator +from overrides import overrides # pyright: ignore[reportUnknownVariableType] +from pydantic import ( + AnyUrl, + ConstrainedStr, + root_validator, # pyright: ignore[reportUnknownVariableType] + validator, # pyright: ignore[reportUnknownVariableType] +) from . import errors @@ -54,20 +59,20 @@ class PriorityString(enum.IntEnum): PriorityValue = Union[int, Literal["always", "prefer", "defer"]] +def _alias_generator(value: str) -> str: + return value.replace("_", "-") + + class PackageRepository(pydantic.BaseModel, abc.ABC): """The base class for package repositories.""" class Config: # pylint: disable=too-few-public-methods """Pydantic model configuration.""" - # pyright: reportUnknownMemberType=false - # pyright: reportUnknownVariableType=false - # pyright: reportUnknownLambdaType=false - validate_assignment = True allow_mutation = False allow_population_by_field_name = True - alias_generator = lambda s: s.replace("_", "-") # noqa: E731 + alias_generator = _alias_generator extra = "forbid" type: Literal["apt"] @@ -113,7 +118,7 @@ def marshal(self) -> Dict[str, Union[str, int]]: @classmethod def unmarshal(cls, data: Mapping[str, Any]) -> "PackageRepository": """Create a package repository object from the given data.""" - if not isinstance(data, dict): # pyright: reportUnnecessaryIsInstance=false + if not isinstance(data, dict): # pyright: ignore[reportUnnecessaryIsInstance] raise errors.PackageRepositoryValidationError( url=str(data), brief="invalid object.", @@ -133,13 +138,15 @@ def unmarshal(cls, data: Mapping[str, Any]) -> "PackageRepository": @classmethod def unmarshal_package_repositories( - cls, data: Optional[List[Any]] + cls, data: Optional[List[Dict[str, Any]]] ) -> List["PackageRepository"]: """Create multiple package repositories from the given data.""" repositories: List[PackageRepository] = [] if data is not None: - if not isinstance(data, list): + if not isinstance( + data, list + ): # pyright: ignore[reportUnnecessaryIsInstance] raise errors.PackageRepositoryValidationError( url=str(data), brief="invalid list object.", diff --git a/craft_archives/repo/projects.py b/craft_archives/repo/projects.py index ae3a6ee..97d054d 100644 --- a/craft_archives/repo/projects.py +++ b/craft_archives/repo/projects.py @@ -25,6 +25,6 @@ def validate_repository(data: Dict[str, Any]) -> None: :param data: The repository data to validate. """ - if not isinstance(data, dict): # pyright: reportUnnecessaryIsInstance=false + if not isinstance(data, dict): # pyright: ignore[reportUnnecessaryIsInstance] raise TypeError("value must be a dictionary") PackageRepository.unmarshal(data) diff --git a/pyproject.toml b/pyproject.toml index 6b51d33..5999f01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,7 +105,7 @@ strict = ["craft_archives"] pythonVersion = "3.8" pythonPlatform = "Linux" venvPath = ".tox" -venv = "py38" +venv = "typing" [tool.mypy] python_version = "3.8" diff --git a/tests/unit/repo/test_apt_ppa.py b/tests/unit/repo/test_apt_ppa.py index b5f7391..793f3e1 100644 --- a/tests/unit/repo/test_apt_ppa.py +++ b/tests/unit/repo/test_apt_ppa.py @@ -17,14 +17,13 @@ from unittest.mock import call -import launchpadlib +import launchpadlib.launchpad import pytest from craft_archives.repo import apt_ppa, errors @pytest.fixture(autouse=True) def mock_launchpad(mocker): - # pyright: reportGeneralTypeIssues=false m = mocker.patch( "craft_archives.repo.apt_ppa.Launchpad", spec=launchpadlib.launchpad.Launchpad ) diff --git a/tests/unit/repo/test_package_repository.py b/tests/unit/repo/test_package_repository.py index ede9c6f..3b097be 100644 --- a/tests/unit/repo/test_package_repository.py +++ b/tests/unit/repo/test_package_repository.py @@ -505,7 +505,9 @@ def test_unmarshal_package_repositories_list_none(): def test_unmarshal_package_repositories_invalid_data(): with pytest.raises(errors.PackageRepositoryValidationError) as raised: - PackageRepository.unmarshal_package_repositories("not-a-list") + PackageRepository.unmarshal_package_repositories( + "not-a-list" + ) # pyright: ignore[reportGeneralTypeIssues] err = raised.value assert str(err) == ( diff --git a/tox.ini b/tox.ini index c3e366c..603036d 100644 --- a/tox.ini +++ b/tox.ini @@ -88,7 +88,7 @@ allowlist_externals = commands_pre = mypy: mkdir -p .mypy_cache commands = - pyright: pyright --lib {posargs} + pyright: pyright {posargs} mypy: mypy --install-types --non-interactive . [testenv:format-{black,ruff,codespell}]