From d16ff78022c6773c5edd109f4387d1494aebd788 Mon Sep 17 00:00:00 2001 From: Georges Toth Date: Mon, 4 Nov 2024 00:19:48 +0100 Subject: [PATCH] linter fixes --- .editorconfig | 2 +- openhab/client.py | 26 +++--- openhab/command_types.py | 20 ++--- openhab/config.py | 4 +- openhab/items.py | 40 ++++----- openhab/rules.py | 2 +- pyproject.toml | 182 ++++++++++++++++++++------------------- tests/test_basic.py | 1 - 8 files changed, 140 insertions(+), 137 deletions(-) diff --git a/.editorconfig b/.editorconfig index 3f8cb9d..938f224 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,5 +12,5 @@ max_line_length = 240 ij_continuation_indent_size = 2 ij_python_blank_line_at_file_end = true -[{*.yml_sample,*.yaml_sample,*.yml,*.yaml}] +[{*.yml_sample,*.yaml_sample,*.yml,*.yaml,*.toml}] indent_size = 2 diff --git a/openhab/client.py b/openhab/client.py index f692fe8..41d6271 100644 --- a/openhab/client.py +++ b/openhab/client.py @@ -43,7 +43,7 @@ def __init__( password: typing.Optional[str] = None, http_auth: typing.Optional[httpx.Auth] = None, timeout: typing.Optional[float] = None, - oauth2_config: typing.Optional[typing.Dict[str, typing.Any]] = None, + oauth2_config: typing.Optional[dict[str, typing.Any]] = None, ) -> None: """Class constructor. @@ -136,7 +136,7 @@ def _check_req_return(req: httpx.Response) -> None: if not 200 <= req.status_code < 300: req.raise_for_status() - def req_get(self, uri_path: str, params: typing.Optional[typing.Union[typing.Dict[str, typing.Any], list, tuple]] = None) -> typing.Any: + def req_get(self, uri_path: str, params: typing.Optional[typing.Union[dict[str, typing.Any], list, tuple]] = None) -> typing.Any: """Helper method for initiating a HTTP GET request. Besides doing the actual request, it also checks the return value and returns the resulting decoded @@ -155,7 +155,7 @@ def req_get(self, uri_path: str, params: typing.Optional[typing.Union[typing.Dic def req_post( self, uri_path: str, - data: typing.Optional[typing.Union[str, bytes, typing.Mapping[str, typing.Any], typing.Iterable[typing.Tuple[str, typing.Optional[str]]]]] = None, + data: typing.Optional[typing.Union[str, bytes, typing.Mapping[str, typing.Any], typing.Iterable[tuple[str, typing.Optional[str]]]]] = None, ) -> None: """Helper method for initiating a HTTP POST request. @@ -207,7 +207,7 @@ def req_put( self._check_req_return(r) # fetch all items - def fetch_all_items(self) -> typing.Dict[str, openhab.items.Item]: + def fetch_all_items(self) -> dict[str, openhab.items.Item]: """Returns all items defined in openHAB. Returns: @@ -317,7 +317,7 @@ def logout(self) -> bool: return res.status_code == 200 - def _oauth2_token_updater(self, token: typing.Dict[str, typing.Any], refresh_token: typing.Any = None, access_token: typing.Any = None) -> None: + def _oauth2_token_updater(self, token: dict[str, typing.Any], refresh_token: typing.Any = None, access_token: typing.Any = None) -> None: if self.oauth2_config is None: raise ValueError('OAuth2 configuration is not set; invalid action!') @@ -329,15 +329,15 @@ def _oauth2_token_updater(self, token: typing.Dict[str, typing.Any], refresh_tok def create_or_update_item( self, name: str, - _type: typing.Union[str, typing.Type[openhab.items.Item]], + _type: typing.Union[str, type[openhab.items.Item]], quantity_type: typing.Optional[str] = None, label: typing.Optional[str] = None, category: typing.Optional[str] = None, - tags: typing.Optional[typing.List[str]] = None, - group_names: typing.Optional[typing.List[str]] = None, - group_type: typing.Optional[typing.Union[str, typing.Type[openhab.items.Item]]] = None, + tags: typing.Optional[list[str]] = None, + group_names: typing.Optional[list[str]] = None, + group_type: typing.Optional[typing.Union[str, type[openhab.items.Item]]] = None, function_name: typing.Optional[str] = None, - function_params: typing.Optional[typing.List[str]] = None, + function_params: typing.Optional[list[str]] = None, ) -> None: """Creates a new item in openHAB if there is no item with name 'name' yet. @@ -359,7 +359,7 @@ def create_or_update_item( Can be one of ['EQUALITY', 'AND', 'OR', 'NAND', 'NOR', 'AVG', 'SUM', 'MAX', 'MIN', 'COUNT', 'LATEST', 'EARLIEST'] function_params: Optional list of function params (no documentation found), depending on function name. """ - paramdict: typing.Dict[str, typing.Union[str, typing.List[str], typing.Dict[str, typing.Union[str, typing.List[str]]]]] = {} + paramdict: dict[str, typing.Union[str, list[str], dict[str, typing.Union[str, list[str]]]]] = {} if isinstance(_type, type): if issubclass(_type, openhab.items.Item): @@ -425,7 +425,7 @@ def get_item_persistence( page: int = 0, page_length: int = 0, boundary: bool = False, - ) -> typing.Iterator[typing.Dict[str, typing.Union[str, int]]]: + ) -> typing.Iterator[dict[str, typing.Union[str, int]]]: """Method for fetching persistence data for a given item. Args: @@ -443,7 +443,7 @@ def get_item_persistence( "state": "23" } """ - params: typing.Dict[str, typing.Any] = { + params: dict[str, typing.Any] = { 'boundary': str(boundary).lower(), 'page': page, 'pagelength': page_length, diff --git a/openhab/command_types.py b/openhab/command_types.py index 7988adb..6346431 100644 --- a/openhab/command_types.py +++ b/openhab/command_types.py @@ -34,7 +34,7 @@ class CommandType(metaclass=abc.ABCMeta): """Base command type class.""" TYPENAME = '' - SUPPORTED_TYPENAMES: typing.List[str] = [] + SUPPORTED_TYPENAMES: list[str] = [] UNDEF = 'UNDEF' NULL = 'NULL' UNDEFINED_STATES = [UNDEF, NULL] @@ -48,8 +48,8 @@ def is_undefined(cls, value: typing.Any) -> bool: def get_type_for( cls, typename: str, - parent_cls: typing.Optional[typing.Type['CommandType']] = None, - ) -> typing.Union[typing.Type['CommandType'], None]: + parent_cls: typing.Optional[type['CommandType']] = None, + ) -> typing.Union[type['CommandType'], None]: """Get a class type for a given typename.""" if parent_cls is None: parent_cls = CommandType @@ -230,7 +230,7 @@ class ColorType(CommandType): SUPPORTED_TYPENAMES = [TYPENAME] @classmethod - def parse(cls, value: str) -> typing.Optional[typing.Tuple[float, float, float]]: + def parse(cls, value: str) -> typing.Optional[tuple[float, float, float]]: """Parse a given value.""" if value in ColorType.UNDEFINED_STATES: return None @@ -251,7 +251,7 @@ def parse(cls, value: str) -> typing.Optional[typing.Tuple[float, float, float]] return h, s, b @classmethod - def validate(cls, value: typing.Union[str, typing.Tuple[float, float, float]]) -> None: + def validate(cls, value: typing.Union[str, tuple[float, float, float]]) -> None: """Value validation method. Valid values are in format H,S,B. @@ -283,7 +283,7 @@ class DecimalType(CommandType): SUPPORTED_TYPENAMES = [TYPENAME, 'Quantity'] @classmethod - def parse(cls, value: str) -> typing.Union[None, typing.Tuple[typing.Union[int, float], str]]: + def parse(cls, value: str) -> typing.Union[None, tuple[typing.Union[int, float], str]]: """Parse a given value.""" if value in DecimalType.UNDEFINED_STATES: return None @@ -306,7 +306,7 @@ def parse(cls, value: str) -> typing.Union[None, typing.Tuple[typing.Union[int, raise ValueError @classmethod - def validate(cls, value: typing.Union[float, typing.Tuple[float, str], str]) -> None: + def validate(cls, value: typing.Union[float, tuple[float, str], str]) -> None: """Value validation method. Valid values are any of data_type: @@ -611,7 +611,7 @@ class PointType(CommandType): SUPPORTED_TYPENAMES = [TYPENAME] @classmethod - def parse(cls, value: str) -> typing.Optional[typing.Tuple[float, float, float]]: + def parse(cls, value: str) -> typing.Optional[tuple[float, float, float]]: """Parse a given value.""" if value in PercentType.UNDEFINED_STATES: return None @@ -630,9 +630,7 @@ def parse(cls, value: str) -> typing.Optional[typing.Tuple[float, float, float]] return latitude, longitude, altitude @classmethod - def validate( - cls, value: typing.Optional[typing.Union[str, typing.Tuple[typing.Union[float, int], typing.Union[float, int], typing.Union[float, int]]]] - ) -> None: + def validate(cls, value: typing.Optional[typing.Union[str, tuple[typing.Union[float, int], typing.Union[float, int], typing.Union[float, int]]]]) -> None: """Value validation method. A valid PointType is a tuple of three decimal values representing: diff --git a/openhab/config.py b/openhab/config.py index f57e799..5e6f690 100644 --- a/openhab/config.py +++ b/openhab/config.py @@ -52,7 +52,7 @@ class Oauth2User(pydantic.BaseModel): """Nested user structure within an oauth2 token.""" name: str - roles: typing.List[str] + roles: list[str] class Oauth2Token(pydantic.BaseModel): @@ -62,7 +62,7 @@ class Oauth2Token(pydantic.BaseModel): expires_in: int expires_at: float = time.time() - 10 refresh_token: str - scope: typing.Union[str, typing.List[str]] = 'admin' + scope: typing.Union[str, list[str]] = 'admin' token_type: str user: Oauth2User diff --git a/openhab/items.py b/openhab/items.py index 43596f0..957b17a 100644 --- a/openhab/items.py +++ b/openhab/items.py @@ -34,11 +34,11 @@ class Item: """Base item class.""" - types: typing.Sequence[typing.Type[openhab.command_types.CommandType]] = [] - state_types: typing.Sequence[typing.Type[openhab.command_types.CommandType]] = [] - command_event_types: typing.Sequence[typing.Type[openhab.command_types.CommandType]] = [] - state_event_types: typing.Sequence[typing.Type[openhab.command_types.CommandType]] = [] - state_changed_event_types: typing.Sequence[typing.Type[openhab.command_types.CommandType]] = [] + types: typing.Sequence[type[openhab.command_types.CommandType]] = [] + state_types: typing.Sequence[type[openhab.command_types.CommandType]] = [] + command_event_types: typing.Sequence[type[openhab.command_types.CommandType]] = [] + state_event_types: typing.Sequence[type[openhab.command_types.CommandType]] = [] + state_changed_event_types: typing.Sequence[type[openhab.command_types.CommandType]] = [] TYPENAME = 'unknown' @@ -144,7 +144,7 @@ def unit_of_measure(self) -> str: return self._unitOfMeasure @property - def members(self) -> typing.Dict[str, typing.Any]: + def members(self) -> dict[str, typing.Any]: """If item is a type of Group, it will return all member items for this group. For none group item empty dictionary will be returned. @@ -155,7 +155,7 @@ def members(self) -> typing.Dict[str, typing.Any]: """ return self._members - def _validate_value(self, value: typing.Union[str, typing.Type[openhab.command_types.CommandType]]) -> None: + def _validate_value(self, value: typing.Union[str, type[openhab.command_types.CommandType]]) -> None: """Private method for verifying the new value before modifying the state of the item.""" if self.type_ == 'String': if not isinstance(value, (str, bytes)): @@ -176,7 +176,7 @@ def _validate_value(self, value: typing.Union[str, typing.Type[openhab.command_t else: raise ValueError - def _parse_rest(self, value: str) -> typing.Tuple[str, str]: + def _parse_rest(self, value: str) -> tuple[str, str]: """Parse a REST result into a native object.""" return value, '' @@ -289,7 +289,7 @@ def persistence( page: int = 0, page_length: int = 0, boundary: bool = False, - ) -> typing.Iterator[typing.Dict[str, typing.Union[str, int]]]: + ) -> typing.Iterator[dict[str, typing.Union[str, int]]]: """Method for fetching persistence data for a given item. Args: @@ -321,8 +321,8 @@ class GroupItem(Item): """String item type.""" TYPENAME = 'Group' - types: typing.List[typing.Type[openhab.command_types.CommandType]] = [] - state_types: typing.List[typing.Type[openhab.command_types.CommandType]] = [] + types: list[type[openhab.command_types.CommandType]] = [] + state_types: list[type[openhab.command_types.CommandType]] = [] class StringItem(Item): @@ -382,7 +382,7 @@ def __ne__(self, other: object) -> bool: return not self.__eq__(other) - def _parse_rest(self, value: str) -> typing.Tuple[datetime.datetime, str]: # type: ignore[override] + def _parse_rest(self, value: str) -> tuple[datetime.datetime, str]: # type: ignore[override] """Parse a REST result into a native object. Args: @@ -470,7 +470,7 @@ class NumberItem(Item): types = [openhab.command_types.DecimalType] state_types = types - def _parse_rest(self, value: str) -> typing.Tuple[typing.Union[float, None], str]: # type: ignore[override] + def _parse_rest(self, value: str) -> tuple[typing.Union[float, None], str]: # type: ignore[override] """Parse a REST result into a native object. Args: @@ -499,7 +499,7 @@ def _parse_rest(self, value: str) -> typing.Tuple[typing.Union[float, None], str raise ValueError(f'{self.__class__}: unable to parse value "{value}"') - def _rest_format(self, value: typing.Union[float, typing.Tuple[float, str], str]) -> typing.Union[str, bytes]: + def _rest_format(self, value: typing.Union[float, tuple[float, str], str]) -> typing.Union[str, bytes]: """Format a value before submitting to openHAB. Args: @@ -545,7 +545,7 @@ class DimmerItem(Item): types = [openhab.command_types.OnOffType, openhab.command_types.PercentType, openhab.command_types.IncreaseDecreaseType] state_types = [openhab.command_types.PercentType] - def _parse_rest(self, value: str) -> typing.Tuple[float, str]: # type: ignore[override] + def _parse_rest(self, value: str) -> tuple[float, str]: # type: ignore[override] """Parse a REST result into a native object. Args: @@ -595,7 +595,7 @@ class ColorItem(DimmerItem): types = [openhab.command_types.OnOffType, openhab.command_types.PercentType, openhab.command_types.IncreaseDecreaseType, openhab.command_types.ColorType] state_types = [openhab.command_types.ColorType] - def _parse_rest(self, value: str) -> typing.Tuple[typing.Optional[typing.Tuple[float, float, float]], str]: # type: ignore[override] + def _parse_rest(self, value: str) -> tuple[typing.Optional[tuple[float, float, float]], str]: # type: ignore[override] """Parse a REST result into a native object. Args: @@ -608,7 +608,7 @@ def _parse_rest(self, value: str) -> typing.Tuple[typing.Optional[typing.Tuple[f result = openhab.command_types.ColorType.parse(value) return result, '' - def _rest_format(self, value: typing.Union[typing.Tuple[int, int, float], str, int]) -> str: + def _rest_format(self, value: typing.Union[tuple[int, int, float], str, int]) -> str: """Format a value before submitting to openHAB. Args: @@ -634,7 +634,7 @@ class RollershutterItem(Item): types = [openhab.command_types.UpDownType, openhab.command_types.PercentType, openhab.command_types.StopMoveType] state_types = [openhab.command_types.PercentType] - def _parse_rest(self, value: str) -> typing.Tuple[int, str]: # type: ignore[override] + def _parse_rest(self, value: str) -> tuple[int, str]: # type: ignore[override] """Parse a REST result into a native object. Args: @@ -680,7 +680,7 @@ class LocationItem(Item): types = [openhab.command_types.PointType] state_types = [openhab.command_types.PointType] - def _parse_rest(self, value: str) -> typing.Tuple[typing.Optional[typing.Tuple[float, float, float]], str]: # type: ignore[override] + def _parse_rest(self, value: str) -> tuple[typing.Optional[tuple[float, float, float]], str]: # type: ignore[override] """Parse a REST result into a native object. Args: @@ -692,7 +692,7 @@ def _parse_rest(self, value: str) -> typing.Tuple[typing.Optional[typing.Tuple[f """ return openhab.command_types.PointType.parse(value), '' - def _rest_format(self, value: typing.Union[typing.Tuple[float, float, float], str]) -> str: + def _rest_format(self, value: typing.Union[tuple[float, float, float], str]) -> str: """Format a value before submitting to openHAB. Args: diff --git a/openhab/rules.py b/openhab/rules.py index d3811e2..bdffda5 100644 --- a/openhab/rules.py +++ b/openhab/rules.py @@ -41,6 +41,6 @@ def __init__(self, openhab_conn: 'openhab.client.OpenHAB') -> None: self.openhab = openhab_conn self.logger = logging.getLogger(__name__) - def get(self) -> typing.List[typing.Dict[str, typing.Any]]: + def get(self) -> list[dict[str, typing.Any]]: """Get all rules.""" return self.openhab.req_get('/rules') diff --git a/pyproject.toml b/pyproject.toml index a3035c2..b407115 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,24 +8,24 @@ description = "python library for accessing the openHAB REST API" authors = [{ name = "Georges Toth", email = "georges@trypill.org" }] license = { text = "AGPLv3+" } classifiers = [ - "Development Status :: 5 - Production/Stable", - "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", - "Intended Audience :: Developers", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] keywords = ["openHAB"] requires-python = ">=3.9" dependencies = [ - "python-dateutil~=2.8", - "pydantic<3", - "Authlib~=1.2", - "httpx~=0.24", + "python-dateutil~=2.8", + "pydantic<3", + "Authlib~=1.2", + "httpx~=0.24", ] dynamic = ["version"] @@ -42,20 +42,20 @@ Source = "https://github.com/sim0nx/python-openhab" [project.optional-dependencies] docs = [ - "mkdocs-material", - "mkdocstrings[crystal,python]", + "mkdocs-material", + "mkdocstrings[crystal,python]", ] dev = [ - "mypy", - "ruff", - "types-python-dateutil", - "typeguard", + "mypy", + "ruff", + "types-python-dateutil", + "typeguard", ] test = [ - "pytest", - "pytest-sugar", - "coverage", - "beautifulsoup4", + "pytest", + "pytest-sugar", + "coverage", + "beautifulsoup4", ] [tool.setuptools_scm] @@ -89,77 +89,83 @@ target-version = "py39" [tool.ruff.lint] select = [ - "E", # pycodestyle errors - "W", # pycodestyle warnings - "F", # pyflakes - "I", # isort - "C", # flake8-comprehensions - "B", # flake8-bugbear - "D", # pydocstyle - "N", # pep8-naming - "UP", # pyupgrade - "YTT", # flake8-2020 - "ANN", # flake8-annotations - "ASYNC", # flake8-async - "S", # flake8-bandit - "BLE", # flake8-blind-except - "B", # flake8-bugbear - "A", # flake8-builtins - "COM", # flake8-commas - "C4", # flake8-comprehensions - "DTZ", # flake8-datetimez - "EM103", # flake8-errmsg - dot-format-in-exception - "EXE", # flake8-executable - "ISC", # flake8-implicit-str-concat - "ICN", # flake8-import-conventions - "G", # flake8-logging-format - "INP", # flake8-no-pep420 - "PIE", # flake8-pie - "T20", # flake8-print - "PYI", # flake8-pyi - "RSE", # flake8-raise - "RET", # flake8-return - "SLF", # flake8-self - "SLOT", # flake8-slots - # "SIM", # flake8-simplify - "TID", # flake8-tidy-imports - "TCH", # flake8-type-checking - "PTH", # flake8-use-pathlib - "TD", # flake8-todos - "FIX", # flake8-fixme - "ERA", # eradicate - "PL", # Pylint - "PLC", # Convention - "PLE", # Error - "PLR", # Refactor - "PLW", # Warning - "B904", # reraise-no-cause - "FLY", # flynt - # "PERF", # Perflint - "RUF013", # implicit-optional + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # pyflakes + "I", # isort + "C", # flake8-comprehensions + "B", # flake8-bugbear + "D", # pydocstyle + "N", # pep8-naming + "UP", # pyupgrade + "YTT", # flake8-2020 + "ANN", # flake8-annotations + "ASYNC", # flake8-async + "S", # flake8-bandit + "BLE", # flake8-blind-except + "B", # flake8-bugbear + "A", # flake8-builtins + "COM", # flake8-commas + "C4", # flake8-comprehensions + "DTZ", # flake8-datetimez + "EM103", # flake8-errmsg - dot-format-in-exception + "EXE", # flake8-executable + "ISC", # flake8-implicit-str-concat + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "INP", # flake8-no-pep420 + "PIE", # flake8-pie + "T20", # flake8-print + "PYI", # flake8-pyi + "RSE", # flake8-raise + "RET", # flake8-return + "SLF", # flake8-self + "SLOT", # flake8-slots + # "SIM", # flake8-simplify + "TID", # flake8-tidy-imports + "TCH", # flake8-type-checking + "PTH", # flake8-use-pathlib + "TD", # flake8-todos + "FIX", # flake8-fixme + "ERA", # eradicate + "PL", # Pylint + "PLC", # Convention + "PLE", # Error + "PLR", # Refactor + "PLW", # Warning + "B904", # reraise-no-cause + "FLY", # flynt + # "PERF", # Perflint + "RUF013", # implicit-optional ] unfixable = ['ERA001'] extend-select = ['Q', 'RUF100', 'C90'] flake8-quotes = { inline-quotes = 'single', multiline-quotes = 'single' } ignore = [ - "C901", # too complex - "E501", # line too long - "B008", # do not perform function call in argument defaults - "ANN101", # missing-type-self - "ANN401", # any-type - "ANN002", # missing-type-args - "ANN003", # missing-type-kwargs - "ANN102", # missing-type-cls - "PLR0913", # Too many arguments to function call - "PLR0915", # Too many statements - "PLR2004", # Magic value used in comparison - "PLW0603", # Using the global statement - "PLR0912", # Too many branches - "COM812", # missing-trailing-comma - "ISC001", # single-line-implicit-string-concatenation - "Q001", # bad-quotes-multiline-string + "C901", # too complex + "E501", # line too long + "B008", # do not perform function call in argument defaults + "ANN101", # missing-type-self + "ANN401", # any-type + "ANN002", # missing-type-args + "ANN003", # missing-type-kwargs + "ANN102", # missing-type-cls + "PLR0913", # Too many arguments to function call + "PLR0915", # Too many statements + "PLR2004", # Magic value used in comparison + "PLW0603", # Using the global statement + "PLR0912", # Too many branches + "COM812", # missing-trailing-comma + "ISC001", # single-line-implicit-string-concatenation + "Q001", # bad-quotes-multiline-string ] +[tool.ruff.lint.per-file-ignores] +"tests/*" = [ + "S101", # Use of `assert` detected + "D", # docstring + "RET504", # Unnecessary assignment before `return` statement +] [tool.ruff.format] quote-style = "single" diff --git a/tests/test_basic.py b/tests/test_basic.py index 88c74cc..57f113f 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -5,7 +5,6 @@ import openhab - # ruff: noqa: S101, ANN201, T201