diff --git a/pyproject.pylint_excerpt b/pyproject.pylint_excerpt new file mode 100644 index 000000000..4d1d466b2 --- /dev/null +++ b/pyproject.pylint_excerpt @@ -0,0 +1,141 @@ +[tool.pylint.MAIN] +py-version = "3.11" +ignore = [ + "tests", +] +# Use a conservative default here; 2 should speed up most setups and not hurt +# any too bad. Override on command line as appropriate. +# Disabled for now: https://github.com/PyCQA/pylint/issues/3584 +jobs = 2 +init-hook = """\ + from pathlib import Path; \ + import sys; \ + from pylint.config import find_default_config_files; \ + sys.path.append( \ + str(Path(next(find_default_config_files())).parent.joinpath('pylint/plugins')) + ) \ + """ +load-plugins = [ + "pylint.extensions.code_style", + "pylint.extensions.typing", + "hass_enforce_type_hints", + "hass_imports", + "hass_logger", + "pylint_per_file_ignores", +] +persistent = false +extension-pkg-allow-list = [ + "av.audio.stream", + "av.stream", + "ciso8601", + "orjson", + "cv2", +] +fail-on = [ + "I", +] + +[tool.pylint.BASIC] +class-const-naming-style = "any" +good-names = [ + "_", + "ev", + "ex", + "fp", + "i", + "id", + "j", + "k", + "Run", + "ip", +] + +[tool.pylint."MESSAGES CONTROL"] +# Reasons disabled: +# format - handled by black +# locally-disabled - it spams too much +# duplicate-code - unavoidable +# cyclic-import - doesn't test if both import on load +# abstract-class-little-used - prevents from setting right foundation +# unused-argument - generic callbacks and setup methods create a lot of warnings +# too-many-* - are not enforced for the sake of readability +# too-few-* - same as too-many-* +# abstract-method - with intro of async there are always methods missing +# inconsistent-return-statements - doesn't handle raise +# too-many-ancestors - it's too strict. +# wrong-import-order - isort guards this +# consider-using-f-string - str.format sometimes more readable +# --- +# Pylint CodeStyle plugin +# consider-using-namedtuple-or-dataclass - too opinionated +# consider-using-assignment-expr - decision to use := better left to devs +disable = [ + "format", + "abstract-method", + "cyclic-import", + "duplicate-code", + "inconsistent-return-statements", + "locally-disabled", + "not-context-manager", + "too-few-public-methods", + "too-many-ancestors", + "too-many-arguments", + "too-many-branches", + "too-many-instance-attributes", + "too-many-lines", + "too-many-locals", + "too-many-public-methods", + "too-many-return-statements", + "too-many-statements", + "too-many-boolean-expressions", + "unused-argument", + "wrong-import-order", + "consider-using-f-string", + "consider-using-namedtuple-or-dataclass", + "consider-using-assignment-expr", + "raise-missing-from", + "missing-class-docstring", + "missing-function-docstring", + "missing-module-docstring", + "too-many-nested-blocks", +] +# for now (20201031) added the below while we are codemerging/-improving +# missing-class-docstring +# missing-function-docstring +# missing-module-docstring +# too-many-nested-blocks => inherent with fixing complexity +enable = [ + #"useless-suppression", # temporarily every now and then to clean them up + "use-symbolic-message-instead", +] + +[tool.pylint.REPORTS] +score = false + +[tool.pylint.TYPECHECK] +ignored-classes = [ + "_CountingAttr", # for attrs +] +mixin-class-rgx = ".*[Mm]ix[Ii]n" + +[tool.pylint.FORMAT] +expected-line-ending-format = "LF" + +[tool.pylint.EXCEPTIONS] +overgeneral-exceptions = [ + "builtins.BaseException", + "builtins.Exception", + # "homeassistant.exceptions.HomeAssistantError", # too many issues +] + +[tool.pylint.TYPING] +runtime-typing = false + +[tool.pylint.CODE_STYLE] +max-line-length-suggestions = 72 + +[tool.pylint-per-file-ignores] +# hass-component-root-import: Tests test non-public APIs +# protected-access: Tests do often test internals a lot +# redefined-outer-name: Tests reference fixtures in the test function +"/tests/"="hass-component-root-import,protected-access,redefined-outer-name" diff --git a/pyproject.toml b/pyproject.toml index cef0046cb..1afa389d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,104 +21,65 @@ forced_separate = [ ] combine_as_imports = true -[tool.pylint.MASTER] -ignore = [ - "tests", -] -# Use a conservative default here; 2 should speed up most setups and not hurt -# any too bad. Override on command line as appropriate. -# Disabled for now: https://github.com/PyCQA/pylint/issues/3584 -jobs = 2 -load-plugins = [ - "pylint.extensions.code_style", - "pylint.extensions.typing", -] -persistent = false -extension-pkg-whitelist = [ - "ciso8601", - "cv2", -] +[tool.ruff] +target-version = "py310" -[tool.pylint.BASIC] -good-names = [ - "_", - "ev", - "ex", - "fp", - "i", - "id", - "j", - "k", - "Run", - "T", +select = [ + "B007", # Loop control variable {name} not used within loop body + "B014", # Exception handler with duplicate exception + "C", # complexity + "D", # docstrings + "E", # pycodestyle + "F", # pyflakes/autoflake + "ICN001", # import concentions; {name} should be imported as {asname} + "PGH004", # Use specific rule codes when using noqa + "PLC0414", # Useless import alias. Import alias does not rename original package. + "SIM105", # Use contextlib.suppress({exception}) instead of try-except-pass + "SIM117", # Merge with-statements that use the same scope + "SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys() + "SIM201", # Use {left} != {right} instead of not {left} == {right} + "SIM212", # Use {a} if {a} else {b} instead of {b} if not {a} else {a} + "SIM300", # Yoda conditions. Use 'age == 42' instead of '42 == age'. + "SIM401", # Use get from dict with default instead of an if block + "T20", # flake8-print + "TRY004", # Prefer TypeError exception for invalid type + "RUF006", # Store a reference to the return value of asyncio.create_task + "UP", # pyupgrade + "W", # pycodestyle ] -[tool.pylint."MESSAGES CONTROL"] -# Reasons disabled: -# format - handled by black -# locally-disabled - it spams too much -# duplicate-code - unavoidable -# cyclic-import - doesn't test if both import on load -# abstract-class-little-used - prevents from setting right foundation -# unused-argument - generic callbacks and setup methods create a lot of warnings -# too-many-* - are not enforced for the sake of readability -# too-few-* - same as too-many-* -# abstract-method - with intro of async there are always methods missing -# inconsistent-return-statements - doesn't handle raise -# too-many-ancestors - it's too strict. -# wrong-import-order - isort guards this -disable = [ - "format", - "abstract-method", - "consider-using-f-string", - "cyclic-import", - "duplicate-code", - "fixme", - "inconsistent-return-statements", - "locally-disabled", - "not-context-manager", - "too-few-public-methods", - "too-many-ancestors", - "too-many-arguments", - "too-many-branches", - "too-many-instance-attributes", - "too-many-lines", - "too-many-locals", - "too-many-public-methods", - "too-many-return-statements", - "too-many-statements", - "too-many-boolean-expressions", - "unused-argument", - "wrong-import-order", - "raise-missing-from", - "missing-class-docstring", - "missing-function-docstring", - "missing-module-docstring", - "too-many-nested-blocks", -] -# for now (20201031) added the below while we are codemerging/-improving -# missing-class-docstring -# missing-function-docstring -# missing-module-docstring -# too-many-nested-blocks => inherent with fixing complexity -enable = [ - #"useless-suppression", # temporarily every now and then to clean them up - "use-symbolic-message-instead", +ignore = [ + "D202", # No blank lines allowed after function docstring + "D203", # 1 blank line required before class docstring + "D213", # Multi-line docstring summary should start at the second line + "D406", # Section name should end with a newline + "D407", # Section name underlining + "E501", # line too long + "E731", # do not assign a lambda expression, use a def + # Ignored due to performance: https://github.com/charliermarsh/ruff/issues/2923 + "UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)` ] -[tool.pylint.REPORTS] -score = false +[tool.ruff.flake8-import-conventions.extend-aliases] +voluptuous = "vol" +"homeassistant.helpers.area_registry" = "ar" +"homeassistant.helpers.config_validation" = "cv" +"homeassistant.helpers.device_registry" = "dr" +"homeassistant.helpers.entity_registry" = "er" +"homeassistant.helpers.issue_registry" = "ir" -[tool.pylint.TYPECHECK] -ignored-classes = [ - "_CountingAttr", # for attrs -] +[tool.ruff.flake8-pytest-style] +fixture-parentheses = false -[tool.pylint.FORMAT] -expected-line-ending-format = "LF" +[tool.ruff.pyupgrade] +keep-runtime-typing = true -[tool.pylint.EXCEPTIONS] -overgeneral-exceptions = [ - "builtins.BaseException", - "builtins.Exception", -] +[tool.ruff.per-file-ignores] + +# Allow for main entry & scripts to write to stdout +"homeassistant/__main__.py" = ["T201"] +"homeassistant/scripts/*" = ["T201"] +"script/*" = ["T20"] + +[tool.ruff.mccabe] +max-complexity = 25 diff --git a/scripts/core-testing.sh b/scripts/core-testing.sh index 64d1542d6..e305eef95 100755 --- a/scripts/core-testing.sh +++ b/scripts/core-testing.sh @@ -222,6 +222,17 @@ disallow_untyped_defs = true warn_return_any = true warn_unreachable = true" >> mypy.ini echo "... mypy ..." + echo "Prepping strict without hassfest" + echo "homeassistant.components.plugwise.*" >> .strict-typing + echo "[mypy-homeassistant.components.plugwise.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +warn_return_any = true +warn_unreachable = true" >> mypy.ini script/run-in-env.sh mypy homeassistant/components/plugwise/*.py || exit cd .. echo "... markdownlint ..."