Check if requirement is typed in strict_typing IQS validation (#133415)

* Check if requirement is typed in strict_typing IQS validation

* Apply suggestions from code review

* Apply suggestions from code review

* Return a list

* Adjust

* Improve
pull/133421/head
epenet 2024-12-17 12:53:27 +01:00 committed by GitHub
parent 637614299c
commit e61142c2c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 49 additions and 5 deletions

View File

@ -95,4 +95,7 @@ rules:
comment: |
the fritzconnection lib is not async and relies on requests
changing this might need a bit more efforts to be spent
strict-typing: done
strict-typing:
status: todo
comment: |
Requirements 'fritzconnection==1.14.0' and 'xmltodict==0.13.0' appear untyped

View File

@ -94,4 +94,7 @@ rules:
status: exempt
comment: |
This integration does not use web sessions.
strict-typing: done
strict-typing:
status: todo
comment: |
Requirement 'aioimaplib==1.1.0' appears untyped

View File

@ -93,4 +93,7 @@ rules:
# Platinum
async-dependency: todo
inject-websession: todo
strict-typing: done
strict-typing:
status: todo
comment: |
Requirement 'Mastodon.py==1.8.1' appears untyped

View File

@ -125,4 +125,7 @@ rules:
status: exempt
comment: |
This integration does not use web sessions.
strict-typing: done
strict-typing:
status: todo
comment: |
Requirement 'paho-mqtt==1.6.1' appears untyped

View File

@ -86,4 +86,7 @@ rules:
# Platinum
async-dependency: done
inject-websession: done
strict-typing: done
strict-typing:
status: todo
comment: |
Requirement 'stookwijzer==1.5.1' appears untyped

View File

@ -4,6 +4,7 @@ https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/s
"""
from functools import lru_cache
from importlib import metadata
from pathlib import Path
import re
@ -24,6 +25,29 @@ def _strict_typing_components(strict_typing_file: Path) -> set[str]:
)
def _check_requirements_are_typed(integration: Integration) -> list[str]:
"""Check if all requirements are typed."""
invalid_requirements = []
for requirement in integration.requirements:
requirement_name, requirement_version = requirement.split("==")
# Remove any extras
requirement_name = requirement_name.split("[")[0]
try:
distribution = metadata.distribution(requirement_name)
except metadata.PackageNotFoundError:
# Package not installed locally
continue
if distribution.version != requirement_version:
# Version out of date locally
continue
if not any(file for file in distribution.files if file.name == "py.typed"):
# no py.typed file
invalid_requirements.append(requirement)
return invalid_requirements
def validate(
config: Config, integration: Integration, *, rules_done: set[str]
) -> list[str] | None:
@ -35,4 +59,9 @@ def validate(
"Integration does not have strict typing enabled "
"(is missing from .strict-typing)"
]
if untyped_requirements := _check_requirements_are_typed(integration):
return [
f"Requirements {untyped_requirements} do not conform PEP 561 (https://peps.python.org/pep-0561/)",
"They should be typed and have a 'py.typed' file",
]
return None