Skip to content

Commit

Permalink
Pylint plugin to check that relative imports are used (home-assistant…
Browse files Browse the repository at this point in the history
…#50937)

* Pylint plugin to check that relative imports are used

* Fix existing sites

* Update description message

* Fix typo
  • Loading branch information
KapJI authored May 22, 2021
1 parent b704f0e commit 016abda
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 44 deletions.
3 changes: 1 addition & 2 deletions homeassistant/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@
import jwt

from homeassistant import data_entry_flow
from homeassistant.auth.const import ACCESS_TOKEN_EXPIRATION
from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.util import dt as dt_util

from . import auth_store, models
from .const import GROUP_ID_ADMIN
from .const import ACCESS_TOKEN_EXPIRATION, GROUP_ID_ADMIN
from .mfa_modules import MultiFactorAuthModule, auth_mfa_module_from_config
from .providers import AuthProvider, LoginFlow, auth_provider_from_config

Expand Down
23 changes: 12 additions & 11 deletions homeassistant/components/adguard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,6 @@
from adguardhome import AdGuardHome, AdGuardHomeConnectionError, AdGuardHomeError
import voluptuous as vol

from homeassistant.components.adguard.const import (
CONF_FORCE,
DATA_ADGUARD_CLIENT,
DATA_ADGUARD_VERSION,
DOMAIN,
SERVICE_ADD_URL,
SERVICE_DISABLE_URL,
SERVICE_ENABLE_URL,
SERVICE_REFRESH,
SERVICE_REMOVE_URL,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_HOST,
Expand All @@ -34,6 +23,18 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.entity import DeviceInfo, Entity

from .const import (
CONF_FORCE,
DATA_ADGUARD_CLIENT,
DATA_ADGUARD_VERSION,
DOMAIN,
SERVICE_ADD_URL,
SERVICE_DISABLE_URL,
SERVICE_ENABLE_URL,
SERVICE_REFRESH,
SERVICE_REMOVE_URL,
)

_LOGGER = logging.getLogger(__name__)

SERVICE_URL_SCHEMA = vol.Schema({vol.Required(CONF_URL): cv.url})
Expand Down
9 changes: 2 additions & 7 deletions homeassistant/components/azure_devops/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,13 @@
from aioazuredevops.client import DevOpsClient
import aiohttp

from homeassistant.components.azure_devops.const import (
CONF_ORG,
CONF_PAT,
CONF_PROJECT,
DATA_AZURE_DEVOPS_CLIENT,
DOMAIN,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.entity import DeviceInfo, Entity

from .const import CONF_ORG, CONF_PAT, CONF_PROJECT, DATA_AZURE_DEVOPS_CLIENT, DOMAIN

_LOGGER = logging.getLogger(__name__)

PLATFORMS = ["sensor"]
Expand Down
13 changes: 7 additions & 6 deletions homeassistant/components/blink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@
import voluptuous as vol

from homeassistant.components import persistent_notification
from homeassistant.components.blink.const import (
from homeassistant.config_entries import SOURCE_REAUTH
from homeassistant.const import CONF_FILENAME, CONF_NAME, CONF_PIN, CONF_SCAN_INTERVAL
from homeassistant.core import callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv

from .const import (
DEFAULT_SCAN_INTERVAL,
DOMAIN,
PLATFORMS,
SERVICE_REFRESH,
SERVICE_SAVE_VIDEO,
SERVICE_SEND_PIN,
)
from homeassistant.config_entries import SOURCE_REAUTH
from homeassistant.const import CONF_FILENAME, CONF_NAME, CONF_PIN, CONF_SCAN_INTERVAL
from homeassistant.core import callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv

_LOGGER = logging.getLogger(__name__)

Expand Down
8 changes: 2 additions & 6 deletions homeassistant/components/color_extractor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,6 @@
from colorthief import ColorThief
import voluptuous as vol

from homeassistant.components.color_extractor.const import (
ATTR_PATH,
ATTR_URL,
DOMAIN,
SERVICE_TURN_ON,
)
from homeassistant.components.light import (
ATTR_RGB_COLOR,
DOMAIN as LIGHT_DOMAIN,
Expand All @@ -24,6 +18,8 @@
from homeassistant.helpers import aiohttp_client
import homeassistant.helpers.config_validation as cv

from .const import ATTR_PATH, ATTR_URL, DOMAIN, SERVICE_TURN_ON

_LOGGER = logging.getLogger(__name__)

# Extend the existing light.turn_on service schema
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/somfy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from pymfy.api.devices.category import Category
import voluptuous as vol

from homeassistant.components.somfy import config_flow
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_OPTIMISTIC
from homeassistant.core import HomeAssistant, callback
Expand All @@ -21,7 +20,7 @@
DataUpdateCoordinator,
)

from . import api
from . import api, config_flow
from .const import API, COORDINATOR, DOMAIN

_LOGGER = logging.getLogger(__name__)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/spotify/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import voluptuous as vol

from homeassistant.components.media_player import DOMAIN as MEDIA_PLAYER_DOMAIN
from homeassistant.components.spotify import config_flow
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_CREDENTIALS, CONF_CLIENT_ID, CONF_CLIENT_SECRET
from homeassistant.core import HomeAssistant
Expand All @@ -17,6 +16,7 @@
)
from homeassistant.helpers.typing import ConfigType

from . import config_flow
from .const import (
DATA_SPOTIFY_CLIENT,
DATA_SPOTIFY_ME,
Expand Down
15 changes: 8 additions & 7 deletions homeassistant/components/twentemilieu/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@
from twentemilieu import TwenteMilieu
import voluptuous as vol

from homeassistant.components.twentemilieu.const import (
CONF_HOUSE_LETTER,
CONF_HOUSE_NUMBER,
CONF_POST_CODE,
DATA_UPDATE,
DOMAIN,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ID
from homeassistant.core import HomeAssistant
Expand All @@ -23,6 +16,14 @@
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.typing import ConfigType

from .const import (
CONF_HOUSE_LETTER,
CONF_HOUSE_NUMBER,
CONF_POST_CODE,
DATA_UPDATE,
DOMAIN,
)

SCAN_INTERVAL = timedelta(seconds=3600)

SERVICE_UPDATE = "update"
Expand Down
4 changes: 2 additions & 2 deletions pylint/plugins/hass_constructor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Plugin for constructor definitions."""
from astroid import ClassDef, Const, FunctionDef
from astroid import Const, FunctionDef
from pylint.checkers import BaseChecker
from pylint.interfaces import IAstroidChecker
from pylint.lint import PyLinter
Expand Down Expand Up @@ -43,7 +43,7 @@ def visit_functiondef(self, node: FunctionDef) -> None:
return

# Check that return type is specified and it is "None".
if not isinstance(node.returns, Const) or node.returns.value != None:
if not isinstance(node.returns, Const) or node.returns.value is not None:
self.add_message("hass-constructor-return", node=node)


Expand Down
52 changes: 52 additions & 0 deletions pylint/plugins/hass_imports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Plugin for checking imports."""
from __future__ import annotations

from astroid import Import, ImportFrom, Module
from pylint.checkers import BaseChecker
from pylint.interfaces import IAstroidChecker
from pylint.lint import PyLinter


class HassImportsFormatChecker(BaseChecker): # type: ignore[misc]
"""Checker for imports."""

__implements__ = IAstroidChecker

name = "hass_imports"
priority = -1
msgs = {
"W0011": (
"Relative import should be used",
"hass-relative-import",
"Used when absolute import should be replaced with relative import",
),
}
options = ()

def __init__(self, linter: PyLinter | None = None) -> None:
super().__init__(linter)
self.current_module: str | None = None

def visit_module(self, node: Module) -> None:
"""Called when a Import node is visited."""
self.current_module = node.name

def visit_import(self, node: Import) -> None:
"""Called when a Import node is visited."""
for module, _alias in node.names:
if module.startswith(f"{self.current_module}."):
self.add_message("hass-relative-import", node=node)

def visit_importfrom(self, node: ImportFrom) -> None:
"""Called when a ImportFrom node is visited."""
if node.level is not None:
return
if node.modname == self.current_module or node.modname.startswith(
f"{self.current_module}."
):
self.add_message("hass-relative-import", node=node)


def register(linter: PyLinter) -> None:
"""Register the checker."""
linter.register_checker(HassImportsFormatChecker(linter))
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ load-plugins = [
"pylint.extensions.typing",
"pylint_strict_informational",
"hass_constructor",
"hass_imports",
"hass_logger",
]
persistent = false
Expand Down

0 comments on commit 016abda

Please sign in to comment.