diff --git a/homeassistant/__main__.py b/homeassistant/__main__.py index a6d4e0c7bc9..5e7fab5bd54 100644 --- a/homeassistant/__main__.py +++ b/homeassistant/__main__.py @@ -13,6 +13,7 @@ from homeassistant.const import REQUIRED_PYTHON_VER, RESTART_EXIT_CODE, __versio def set_loop() -> None: """Attempt to use different loop.""" + # pylint: disable=import-outside-toplevel from asyncio.events import BaseDefaultEventLoopPolicy if sys.platform == "win32": @@ -44,6 +45,7 @@ def validate_python() -> None: def ensure_config_path(config_dir: str) -> None: """Validate the configuration directory.""" + # pylint: disable=import-outside-toplevel import homeassistant.config as config_util lib_dir = os.path.join(config_dir, "deps") @@ -77,6 +79,7 @@ def ensure_config_path(config_dir: str) -> None: def get_arguments() -> argparse.Namespace: """Get parsed passed in arguments.""" + # pylint: disable=import-outside-toplevel import homeassistant.config as config_util parser = argparse.ArgumentParser( @@ -214,6 +217,7 @@ def closefds_osx(min_fd: int, max_fd: int) -> None: are guarded. But we can set the close-on-exec flag on everything we want to get rid of. """ + # pylint: disable=import-outside-toplevel from fcntl import fcntl, F_GETFD, F_SETFD, FD_CLOEXEC for _fd in range(min_fd, max_fd): @@ -237,6 +241,7 @@ def cmdline() -> List[str]: async def setup_and_run_hass(config_dir: str, args: argparse.Namespace) -> int: """Set up Home Assistant and run.""" + # pylint: disable=import-outside-toplevel from homeassistant import bootstrap hass = await bootstrap.async_setup_hass( @@ -253,7 +258,7 @@ async def setup_and_run_hass(config_dir: str, args: argparse.Namespace) -> int: return 1 if args.open_ui and hass.config.api is not None: - import webbrowser + import webbrowser # pylint: disable=import-outside-toplevel hass.add_job(webbrowser.open, hass.config.api.base_url) @@ -324,6 +329,7 @@ def main() -> int: args = get_arguments() if args.script is not None: + # pylint: disable=import-outside-toplevel from homeassistant import scripts return scripts.run(args.script) diff --git a/homeassistant/auth/mfa_modules/notify.py b/homeassistant/auth/mfa_modules/notify.py index 8da81a44a61..80d0fa3f973 100644 --- a/homeassistant/auth/mfa_modules/notify.py +++ b/homeassistant/auth/mfa_modules/notify.py @@ -47,28 +47,28 @@ _LOGGER = logging.getLogger(__name__) def _generate_secret() -> str: """Generate a secret.""" - import pyotp + import pyotp # pylint: disable=import-outside-toplevel return str(pyotp.random_base32()) def _generate_random() -> int: """Generate a 8 digit number.""" - import pyotp + import pyotp # pylint: disable=import-outside-toplevel return int(pyotp.random_base32(length=8, chars=list("1234567890"))) def _generate_otp(secret: str, count: int) -> str: """Generate one time password.""" - import pyotp + import pyotp # pylint: disable=import-outside-toplevel return str(pyotp.HOTP(secret).at(count)) def _verify_otp(secret: str, otp: str, count: int) -> bool: """Verify one time password.""" - import pyotp + import pyotp # pylint: disable=import-outside-toplevel return bool(pyotp.HOTP(secret).verify(otp, count)) diff --git a/homeassistant/auth/mfa_modules/totp.py b/homeassistant/auth/mfa_modules/totp.py index 6abddd2123f..142bf32baba 100644 --- a/homeassistant/auth/mfa_modules/totp.py +++ b/homeassistant/auth/mfa_modules/totp.py @@ -35,7 +35,7 @@ _LOGGER = logging.getLogger(__name__) def _generate_qr_code(data: str) -> str: """Generate a base64 PNG string represent QR Code image of data.""" - import pyqrcode + import pyqrcode # pylint: disable=import-outside-toplevel qr_code = pyqrcode.create(data) @@ -55,7 +55,7 @@ def _generate_qr_code(data: str) -> str: def _generate_secret_and_qr_code(username: str) -> Tuple[str, str, str]: """Generate a secret, url, and QR code.""" - import pyotp + import pyotp # pylint: disable=import-outside-toplevel ota_secret = pyotp.random_base32() url = pyotp.totp.TOTP(ota_secret).provisioning_uri( @@ -105,7 +105,7 @@ class TotpAuthModule(MultiFactorAuthModule): def _add_ota_secret(self, user_id: str, secret: Optional[str] = None) -> str: """Create a ota_secret for user.""" - import pyotp + import pyotp # pylint: disable=import-outside-toplevel ota_secret: str = secret or pyotp.random_base32() @@ -160,7 +160,7 @@ class TotpAuthModule(MultiFactorAuthModule): def _validate_2fa(self, user_id: str, code: str) -> bool: """Validate two factor authentication code.""" - import pyotp + import pyotp # pylint: disable=import-outside-toplevel ota_secret = self._users.get(user_id) # type: ignore if ota_secret is None: @@ -195,7 +195,7 @@ class TotpSetupFlow(SetupFlow): Return self.async_show_form(step_id='init') if user_input is None. Return self.async_create_entry(data={'result': result}) if finish. """ - import pyotp + import pyotp # pylint: disable=import-outside-toplevel errors: Dict[str, str] = {} diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 5d939d4b34e..ef345de22cf 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -215,6 +215,7 @@ def async_enable_logging( if not log_no_color: try: + # pylint: disable=import-outside-toplevel from colorlog import ColoredFormatter # basicConfig must be called after importing colorlog in order to diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 734f67906ce..5bfc2e0509b 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -1164,6 +1164,7 @@ class MqttAvailability(Entity): async def cleanup_device_registry(hass, device_id): """Remove device registry entry if there are no remaining entities or triggers.""" # Local import to avoid circular dependencies + # pylint: disable=import-outside-toplevel from . import device_trigger device_registry = await hass.helpers.device_registry.async_get_registry() diff --git a/homeassistant/components/mqtt/config_flow.py b/homeassistant/components/mqtt/config_flow.py index d3c6ee819b5..b0ba58158e0 100644 --- a/homeassistant/components/mqtt/config_flow.py +++ b/homeassistant/components/mqtt/config_flow.py @@ -125,6 +125,7 @@ class FlowHandler(config_entries.ConfigFlow): def try_connection(broker, port, username, password, protocol="3.1"): """Test if we can connect to an MQTT broker.""" + # pylint: disable=import-outside-toplevel import paho.mqtt.client as mqtt if protocol == "3.1": diff --git a/homeassistant/components/mqtt/discovery.py b/homeassistant/components/mqtt/discovery.py index 47a7f5a2037..812bb183e1c 100644 --- a/homeassistant/components/mqtt/discovery.py +++ b/homeassistant/components/mqtt/discovery.py @@ -148,6 +148,7 @@ async def async_start( if config_entries_key not in hass.data[CONFIG_ENTRY_IS_SETUP]: if component == "device_automation": # Local import to avoid circular dependencies + # pylint: disable=import-outside-toplevel from . import device_automation await device_automation.async_setup_entry(hass, config_entry) diff --git a/homeassistant/components/tensorflow/image_processing.py b/homeassistant/components/tensorflow/image_processing.py index 26cf0fed5e8..3638cbafb9f 100644 --- a/homeassistant/components/tensorflow/image_processing.py +++ b/homeassistant/components/tensorflow/image_processing.py @@ -92,7 +92,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" # These imports shouldn't be moved to the top, because they depend on code from the model_dir. # (The model_dir is created during the manual setup process. See integration docs.) - import tensorflow as tf + import tensorflow as tf # pylint: disable=import-outside-toplevel + + # pylint: disable=import-outside-toplevel from object_detection.utils import label_map_util except ImportError: _LOGGER.error( @@ -104,7 +106,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): try: # Display warning that PIL will be used if no OpenCV is found. - import cv2 # noqa: F401 pylint: disable=unused-import + import cv2 # noqa: F401 pylint: disable=unused-import, import-outside-toplevel except ImportError: _LOGGER.warning( "No OpenCV library found. TensorFlow will process image with " @@ -281,7 +283,7 @@ class TensorFlowImageProcessor(ImageProcessingEntity): """Process the image.""" try: - import cv2 # pylint: disable=import-error + import cv2 # pylint: disable=import-error, import-outside-toplevel img = cv2.imdecode(np.asarray(bytearray(image)), cv2.IMREAD_UNCHANGED) inp = img[:, :, [2, 1, 0]] # BGR->RGB diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index 57c4fbe6199..4e3f2e9af57 100644 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -1,4 +1,5 @@ """Support for Z-Wave.""" +# pylint: disable=import-outside-toplevel import asyncio import copy from importlib import import_module diff --git a/homeassistant/components/zwave/config_flow.py b/homeassistant/components/zwave/config_flow.py index b570e31c128..6d7dc012e85 100644 --- a/homeassistant/components/zwave/config_flow.py +++ b/homeassistant/components/zwave/config_flow.py @@ -1,4 +1,5 @@ """Config flow to configure Z-Wave.""" +# pylint: disable=import-outside-toplevel from collections import OrderedDict import logging diff --git a/homeassistant/components/zwave/node_entity.py b/homeassistant/components/zwave/node_entity.py index f1b76075ae8..a9a4bf22b8b 100644 --- a/homeassistant/components/zwave/node_entity.py +++ b/homeassistant/components/zwave/node_entity.py @@ -1,4 +1,5 @@ """Entity class that represents Z-Wave node.""" +# pylint: disable=import-outside-toplevel from itertools import count import logging diff --git a/homeassistant/config.py b/homeassistant/config.py index cdaa30dc049..169f3c77197 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -814,6 +814,7 @@ async def async_check_ha_config_file(hass: HomeAssistant) -> Optional[str]: This method is a coroutine. """ + # pylint: disable=import-outside-toplevel import homeassistant.helpers.check_config as check_config res = await check_config.async_check_ha_config_file(hass) @@ -831,6 +832,7 @@ def async_notify_setup_error( This method must be run in the event loop. """ + # pylint: disable=import-outside-toplevel from homeassistant.components import persistent_notification errors = hass.data.get(DATA_PERSISTENT_ERRORS) diff --git a/homeassistant/core.py b/homeassistant/core.py index d9155ece2d3..54f1c1cd366 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -230,6 +230,7 @@ class HomeAssistant: await self.async_start() if attach_signals: + # pylint: disable=import-outside-toplevel from homeassistant.helpers.signal import async_register_signal_handling async_register_signal_handling(self) diff --git a/homeassistant/helpers/data_entry_flow.py b/homeassistant/helpers/data_entry_flow.py index 05f49cd9f53..2b92887eac3 100644 --- a/homeassistant/helpers/data_entry_flow.py +++ b/homeassistant/helpers/data_entry_flow.py @@ -29,7 +29,7 @@ class _BaseFlowManagerView(HomeAssistantView): if result["type"] != data_entry_flow.RESULT_TYPE_FORM: return result - import voluptuous_serialize + import voluptuous_serialize # pylint: disable=import-outside-toplevel data = result.copy() diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index 8a4b4bc2b76..27ab35dbb3c 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -118,7 +118,7 @@ def async_track_template( variables: Optional[Dict[str, Any]] = None, ) -> CALLBACK_TYPE: """Add a listener that track state changes with template condition.""" - from . import condition + from . import condition # pylint: disable=import-outside-toplevel # Local variable to keep track of if the action has already been triggered already_triggered = False diff --git a/homeassistant/helpers/sun.py b/homeassistant/helpers/sun.py index 45ff06f16de..818010c3410 100644 --- a/homeassistant/helpers/sun.py +++ b/homeassistant/helpers/sun.py @@ -19,7 +19,8 @@ DATA_LOCATION_CACHE = "astral_location_cache" @bind_hass def get_astral_location(hass: HomeAssistantType) -> "astral.Location": """Get an astral location for the current Home Assistant configuration.""" - from astral import Location + + from astral import Location # pylint: disable=import-outside-toplevel latitude = hass.config.latitude longitude = hass.config.longitude @@ -58,7 +59,7 @@ def get_location_astral_event_next( offset: Optional[datetime.timedelta] = None, ) -> datetime.datetime: """Calculate the next specified solar event.""" - from astral import AstralError + from astral import AstralError # pylint: disable=import-outside-toplevel if offset is None: offset = datetime.timedelta() @@ -92,7 +93,7 @@ def get_astral_event_date( date: Union[datetime.date, datetime.datetime, None] = None, ) -> Optional[datetime.datetime]: """Calculate the astral event time for the specified date.""" - from astral import AstralError + from astral import AstralError # pylint: disable=import-outside-toplevel location = get_astral_location(hass) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 5cd15fefd99..8c7b103f834 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -505,6 +505,7 @@ def expand(hass: HomeAssistantType, *args: Any) -> Iterable[State]: # ignore other types continue + # pylint: disable=import-outside-toplevel from homeassistant.components import group if split_entity_id(entity_id)[0] == group.DOMAIN: diff --git a/homeassistant/loader.py b/homeassistant/loader.py index b2e1fa74fba..f8b9ba55aa1 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -70,7 +70,7 @@ async def _async_get_custom_components( return {} try: - import custom_components + import custom_components # pylint: disable=import-outside-toplevel except ImportError: return {} @@ -127,6 +127,7 @@ async def async_get_custom_components( async def async_get_config_flows(hass: "HomeAssistant") -> Set[str]: """Return cached list of config flows.""" + # pylint: disable=import-outside-toplevel from homeassistant.generated.config_flows import FLOWS flows: Set[str] = set() @@ -317,7 +318,7 @@ async def async_get_integration(hass: "HomeAssistant", domain: str) -> Integrati event.set() return integration - from homeassistant import components + from homeassistant import components # pylint: disable=import-outside-toplevel integration = await hass.async_add_executor_job( Integration.resolve_from_root, hass, components, domain diff --git a/homeassistant/scripts/benchmark/__init__.py b/homeassistant/scripts/benchmark/__init__.py index 2bc821c8495..69de7970745 100644 --- a/homeassistant/scripts/benchmark/__init__.py +++ b/homeassistant/scripts/benchmark/__init__.py @@ -155,6 +155,7 @@ async def logbook_filtering_attributes(hass): @benchmark async def _logbook_filtering(hass, last_changed, last_updated): + # pylint: disable=import-outside-toplevel from homeassistant.components import logbook entity_id = "test.entity" diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index c7ef1e93781..c5224f8f959 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -34,6 +34,7 @@ ERROR_STR = "General Errors" def color(the_color, *args, reset=None): """Color helper.""" + # pylint: disable=import-outside-toplevel from colorlog.escape_codes import escape_codes, parse_colors try: diff --git a/homeassistant/scripts/credstash.py b/homeassistant/scripts/credstash.py index f90ab5f793e..99227d81b66 100644 --- a/homeassistant/scripts/credstash.py +++ b/homeassistant/scripts/credstash.py @@ -29,7 +29,7 @@ def run(args): "value", help="The value to save when putting a secret", nargs="?", default=None ) - # pylint: disable=import-error, no-member + # pylint: disable=import-error, no-member, import-outside-toplevel import credstash args = parser.parse_args(args) diff --git a/homeassistant/scripts/keyring.py b/homeassistant/scripts/keyring.py index 594d897ee4c..0622b8c3d45 100644 --- a/homeassistant/scripts/keyring.py +++ b/homeassistant/scripts/keyring.py @@ -26,7 +26,9 @@ def run(args): ) parser.add_argument("name", help="Name of the secret", nargs="?", default=None) - import keyring + import keyring # pylint: disable=import-outside-toplevel + + # pylint: disable=import-outside-toplevel from keyring.util import platform_ as platform args = parser.parse_args(args) diff --git a/pylintrc b/pylintrc index 125062c8cfe..bb51444447a 100644 --- a/pylintrc +++ b/pylintrc @@ -35,7 +35,6 @@ disable= cyclic-import, duplicate-code, global-statement, - import-outside-toplevel, inconsistent-return-statements, locally-disabled, not-context-manager,