From 970094b404dfce572a8b6570e8c59fb48b41f187 Mon Sep 17 00:00:00 2001 From: virtualdj Date: Sat, 10 Aug 2024 11:10:54 +0200 Subject: [PATCH 1/4] Test implementazione devcontainer dedicato --- .devcontainer/devcontainer.json | 62 ++++ .devcontainer/scripts/dev-branch | 7 + .devcontainer/scripts/develop | 35 ++ .devcontainer/scripts/lint | 8 + .devcontainer/scripts/setup | 28 ++ .devcontainer/scripts/specific-version | 8 + .devcontainer/scripts/upgrade | 7 + .gitignore | 132 +++++++- .pre-commit-config.yaml | 29 ++ .vscode/extensions.json | 7 + .vscode/launch.json | 48 +++ .vscode/settings.default.json | 10 + .vscode/tasks.json | 47 +++ README.md | 1 + config/configuration.yaml | 24 ++ pyproject.toml | 430 +++++++++++++++++++++++++ requirements_ha.txt | 8 + 17 files changed, 890 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/devcontainer.json create mode 100755 .devcontainer/scripts/dev-branch create mode 100755 .devcontainer/scripts/develop create mode 100755 .devcontainer/scripts/lint create mode 100755 .devcontainer/scripts/setup create mode 100755 .devcontainer/scripts/specific-version create mode 100755 .devcontainer/scripts/upgrade create mode 100644 .pre-commit-config.yaml create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.default.json create mode 100644 .vscode/tasks.json create mode 100644 config/configuration.yaml create mode 100644 pyproject.toml create mode 100644 requirements_ha.txt diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..4f8c128 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,62 @@ +{ + "name": "Home Assistant Integration Dev", + "image": "mcr.microsoft.com/devcontainers/python:3.12", + "postCreateCommand": ".devcontainer/scripts/setup", + "containerEnv": { + "PYTHONASYNCIODEBUG": "1" + }, + "runArgs": ["-e", "GIT_EDITOR=code --wait"], + "forwardPorts": [ + 8123 + ], + "portsAttributes": { + "8123": { + "label": "Home Assistant", + "onAutoForward": "notify" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "charliermarsh.ruff", + "github.vscode-pull-request-github", + "ms-python.pylint", + "ms-python.python", + "ms-python.vscode-pylance", + "redhat.vscode-yaml", + "esbenp.prettier-vscode", + "ryanluker.vscode-coverage-gutters", + "thibault-vanderseypen.i18n-json-editor" + ], + "settings": { + "files.eol": "\n", + "editor.tabSize": 4, + "pylint.importStrategy": "fromEnvironment", + //"python.pythonPath": "/usr/local/bin/python3", + "python.defaultInterpreterPath": "/usr/local/bin/python", + "python.analysis.autoSearchPaths": true, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.formatOnSave": true + }, + "editor.formatOnPaste": false, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "files.trimTrailingWhitespace": true, + "[markdown]": { + "files.trimTrailingWhitespace": false + }, + "i18nJsonEditor.forceKeyUPPERCASE": false, + "i18nJsonEditor.supportedFolders": [ + "translations", + "i18n" + ] + } + } + }, + "remoteUser": "vscode", + "features": { + "ghcr.io/devcontainers/features/rust:1": {} + //"ghcr.io/devcontainers-contrib/features/ffmpeg-apt-get:1": {} + } +} diff --git a/.devcontainer/scripts/dev-branch b/.devcontainer/scripts/dev-branch new file mode 100755 index 0000000..942fd95 --- /dev/null +++ b/.devcontainer/scripts/dev-branch @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/../.." + +python3 -m pip --disable-pip-version-check install --upgrade git+https://github.com/home-assistant/home-assistant.git@dev diff --git a/.devcontainer/scripts/develop b/.devcontainer/scripts/develop new file mode 100755 index 0000000..9528728 --- /dev/null +++ b/.devcontainer/scripts/develop @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/../.." + +# Create config dir if not present +if [[ ! -d "${PWD}/config" ]]; then + mkdir -p "${PWD}/config" + hass --config "${PWD}/config" --script ensure_config +fi +if ! grep -R "^logger:" config/configuration.yaml >> /dev/null;then +echo -n " +logger: + default: info + logs: + homeassistant.components.viva: debug +" >> config/configuration.yaml +fi +if ! grep -R "debugpy:" config/configuration.yaml >> /dev/null;then +echo " +# Uncomment the line below if you want to use debugger +# debugpy: +" >> config/configuration.yaml +fi + + +# Set the path to custom_components +## This let's us have the structure we want /custom_components/ake_dev +## while at the same time have Home Assistant configuration inside /config +## without resulting to symlinks. +export PYTHONPATH="${PYTHONPATH}:${PWD}/custom_components" + +# Start Home Assistant +hass --config "${PWD}/config" --debug diff --git a/.devcontainer/scripts/lint b/.devcontainer/scripts/lint new file mode 100755 index 0000000..8aa9caa --- /dev/null +++ b/.devcontainer/scripts/lint @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/../.." + +#ruff format . +ruff check . --fix diff --git a/.devcontainer/scripts/setup b/.devcontainer/scripts/setup new file mode 100755 index 0000000..89dc727 --- /dev/null +++ b/.devcontainer/scripts/setup @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/../.." + +# Install libpcap and libturbojpeg to avoid errors in Home Assistant +sudo apt-get update +sudo apt-get install -y libpcap-dev libturbojpeg0 + +# Install uv +python3 -m pip install uv --user --disable-pip-version-check + +# Install Home Assistant dependencies +uv pip install --system --prefix "/home/vscode/.local/" --requirement requirements_ha.txt + +# Install custom_component dependencies +uv pip install --system --prefix "/home/vscode/.local/" --requirement requirements.txt + +# Set workspace directory as safe in git +git config --global --add safe.directory ${PWD} +#pre-commit install + +# Restart Python Language Server in VSCode to see the correct linting +echo "*********************************************" +echo "* To fix linting in VSCode, press F1 and *" +echo "* choose 'Python: Restart Language Server' *" +echo "*********************************************" diff --git a/.devcontainer/scripts/specific-version b/.devcontainer/scripts/specific-version new file mode 100755 index 0000000..726b41a --- /dev/null +++ b/.devcontainer/scripts/specific-version @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/../.." + +read -p 'Set Home Assistant version: ' -r version +python3 -m pip --disable-pip-version-check install --upgrade homeassistant=="$version" diff --git a/.devcontainer/scripts/upgrade b/.devcontainer/scripts/upgrade new file mode 100755 index 0000000..c87a647 --- /dev/null +++ b/.devcontainer/scripts/upgrade @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/../.." + +python3 -m pip install --upgrade --pre homeassistant diff --git a/.gitignore b/.gitignore index ce8fa4d..2f367cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,133 @@ +# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] -.idea/ \ No newline at end of file +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# Home Assistant Config +/config/* +!/config/configuration.yaml \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..8d8aac4 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,29 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.1 + hooks: + - id: ruff + args: + - --fix + - id: ruff-format + files: ^((homeassistant|custom_components|pylint|script|tests)/.+)?[^/]+\.py$ + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-json + exclude: (.vscode|.devcontainer) + - id: pretty-format-json + args: ['--autofix', '--no-ensure-ascii', '--top-keys=domain,name'] + files: manifest.json + - id: pretty-format-json + args: ['--autofix', '--no-ensure-ascii', '--top-keys=name'] + files: hacs.json + - id: pretty-format-json + args: ['--autofix', '--no-ensure-ascii', '--no-sort-keys'] + files: (/strings\.json$|translations/.+\.json$) + - id: check-yaml + args: ['--unsafe'] + - id: check-added-large-files + - id: check-shebang-scripts-are-executable diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..8a5d7d4 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "charliermarsh.ruff", + "esbenp.prettier-vscode", + "ms-python.python" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2605911 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Home Assistant", + "type": "debugpy", + "request": "launch", + "module": "homeassistant", + "justMyCode": false, + "args": [ + "--debug", + "-c", + "config" + ], + }, + /* + { + // Example of attaching to local debug server + "name": "Python: Attach Local", + "type": "python", + "request": "attach", + "port": 5678, + "host": "localhost", + "pathMappings": [ + { + "localRoot": "${workspaceFolder}", + "remoteRoot": "." + } + ] + }, + { + // Example of attaching to my production server + "name": "Python: Attach Remote", + "type": "python", + "request": "attach", + "port": 5678, + "host": "homeassistant.local", + "pathMappings": [ + { + "localRoot": "${workspaceFolder}", + "remoteRoot": "/usr/src/homeassistant" + } + ] + } + */ + ] +} diff --git a/.vscode/settings.default.json b/.vscode/settings.default.json new file mode 100644 index 0000000..681698d --- /dev/null +++ b/.vscode/settings.default.json @@ -0,0 +1,10 @@ +{ + // Please keep this file in sync with settings in home-assistant/.devcontainer/devcontainer.json + // Added --no-cov to work around TypeError: message must be set + // https://github.com/microsoft/vscode-python/issues/14067 + "python.testing.pytestArgs": ["--no-cov"], + // https://code.visualstudio.com/docs/python/testing#_pytest-configuration-settings + "python.testing.pytestEnabled": false, + // https://code.visualstudio.com/docs/python/linting#_general-settings + "pylint.importStrategy": "fromEnvironment" +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..9942129 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,47 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Run Home Assistant Core", + "type": "shell", + "command": ".devcontainer/scripts/develop", + "problemMatcher": [] + }, + { + "label": "Stop Home Assistant Core", + "type": "shell", + "command": "pkill hass ; exit 0", + "problemMatcher": [] + }, + { + "label": "Restart Home Assistant Core", + "type": "shell", + "command": "pkill hass ; .devcontainer/scripts/develop", + "problemMatcher": [] + }, + { + "label": "Upgrade Home Assistant to latest (beta)", + "type": "shell", + "command": ".devcontainer/scripts/upgrade", + "problemMatcher": [] + }, + { + "label": "Load Home Assistant from github - dev branch", + "type": "shell", + "command": ".devcontainer/scripts/dev-branch", + "problemMatcher": [] + }, + { + "label": "Load specific version of Home Assistant", + "type": "shell", + "command": ".devcontainer/scripts/specific-version", + "problemMatcher": [] + }, + { + "label": "Lint with ruff", + "type": "shell", + "command": ".devcontainer/scripts/lint", + "problemMatcher": [] + } + ] +} diff --git a/README.md b/README.md index 5c2aec1..3293752 100644 --- a/README.md +++ b/README.md @@ -92,3 +92,4 @@ Ovviamente non ho alcuna certezza che tutto questo sia la maniera giusta di proc - La [PR #99213](https://github.com/home-assistant/core/pull/99213/files) di Home Assistant per il suggerimento di usare `async_call_later` anziché sommare il timedelta all'ora corrente - La [PR #76793](https://github.com/home-assistant/core/pull/76793/files) di Home Assistant per un esempio di come usare il [cancellation token](https://developers.home-assistant.io/docs/integration_listen_events/#available-event-helpers) restituito da `async_track_point_in_time` - I commit [1](https://github.com/home-assistant/core/commit/c574d86ddbafd6c18995ad9efb297fda3ce4292c) e [2](https://github.com/home-assistant/core/commit/36e7689d139d0f517bbdd8f8f2c11e18936d27b3) per risolvere il warning nei log `[homeassistant.util.loop] Detected blocking call to import_module inside the event loop by custom integration` comparso con la versione 2024.5.0 di Home Assistant e dovuto alle librerie importate +- La configurazione del _devcontainer_ con script ispirati dalla repository [astrandb/viva](https://github.com/astrandb/viva/tree/main/scripts) e da post sulla [community Home Assistant](https://community.home-assistant.io/t/developing-home-assistant-core-in-a-vscode-devcontainer/235650/36) o sulla versione [francofona](https://www.hacf.fr/dev_tuto_1_environnement/) \ No newline at end of file diff --git a/config/configuration.yaml b/config/configuration.yaml new file mode 100644 index 0000000..6cb01d0 --- /dev/null +++ b/config/configuration.yaml @@ -0,0 +1,24 @@ +# Example configuration.yaml entry +default_config: + +logger: + default: info + logs: + custom_components.pun_test: debug + +# Disable ffmpeg +ffmpeg: + ffmpeg_bin: /usr/bin/true + +# Run with debugpy and wait for debugger to connect +# debugpy: +# start: true +# wait: true + +# Enable this part if you want to use CodeSpaces +# http: +# use_x_forwarded_for: true +# trusted_proxies: +# - 127.0.0.1 +# ip_ban_enabled: true +# login_attempts_threshold: 3 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..6dffc1d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,430 @@ +[tool.pylint."MESSAGES CONTROL"] +# Reasons disabled: +# format - handled by ruff +# 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-instance-attributes", + "too-many-lines", + "too-many-locals", + "too-many-public-methods", + "too-many-boolean-expressions", + "wrong-import-order", + "consider-using-f-string", + # "consider-using-namedtuple-or-dataclass", + # "consider-using-assignment-expr", + + # Handled by ruff + # Ref: + "await-outside-async", # PLE1142 + "bad-str-strip-call", # PLE1310 + "bad-string-format-type", # PLE1307 + "bidirectional-unicode", # PLE2502 + "continue-in-finally", # PLE0116 + "duplicate-bases", # PLE0241 + "format-needs-mapping", # F502 + "function-redefined", # F811 + # Needed because ruff does not understand type of __all__ generated by a function + # "invalid-all-format", # PLE0605 + "invalid-all-object", # PLE0604 + "invalid-character-backspace", # PLE2510 + "invalid-character-esc", # PLE2513 + "invalid-character-nul", # PLE2514 + "invalid-character-sub", # PLE2512 + "invalid-character-zero-width-space", # PLE2515 + "logging-too-few-args", # PLE1206 + "logging-too-many-args", # PLE1205 + "missing-format-string-key", # F524 + "mixed-format-string", # F506 + "no-method-argument", # N805 + "no-self-argument", # N805 + "nonexistent-operator", # B002 + "nonlocal-without-binding", # PLE0117 + "not-in-loop", # F701, F702 + "notimplemented-raised", # F901 + "return-in-init", # PLE0101 + "return-outside-function", # F706 + "syntax-error", # E999 + "too-few-format-args", # F524 + "too-many-format-args", # F522 + "too-many-star-expressions", # F622 + "truncated-format-string", # F501 + "undefined-all-variable", # F822 + "undefined-variable", # F821 + "used-prior-global-declaration", # PLE0118 + "yield-inside-async-function", # PLE1700 + "yield-outside-function", # F704 + "anomalous-backslash-in-string", # W605 + "assert-on-string-literal", # PLW0129 + "assert-on-tuple", # F631 + "bad-format-string", # W1302, F + "bad-format-string-key", # W1300, F + "bare-except", # E722 + "binary-op-exception", # PLW0711 + "cell-var-from-loop", # B023 + # "dangerous-default-value", # B006, ruff catches new occurrences, needs more work + "duplicate-except", # B014 + "duplicate-key", # F601 + "duplicate-string-formatting-argument", # F + "duplicate-value", # F + "eval-used", # PGH001 + "exec-used", # S102 + # "expression-not-assigned", # B018, ruff catches new occurrences, needs more work + "f-string-without-interpolation", # F541 + "forgotten-debug-statement", # T100 + "format-string-without-interpolation", # F + # "global-statement", # PLW0603, ruff catches new occurrences, needs more work + "global-variable-not-assigned", # PLW0602 + "implicit-str-concat", # ISC001 + "import-self", # PLW0406 + "inconsistent-quotes", # Q000 + "invalid-envvar-default", # PLW1508 + "keyword-arg-before-vararg", # B026 + "logging-format-interpolation", # G + "logging-fstring-interpolation", # G + "logging-not-lazy", # G + "misplaced-future", # F404 + "named-expr-without-context", # PLW0131 + "nested-min-max", # PLW3301 + # "pointless-statement", # B018, ruff catches new occurrences, needs more work + "raise-missing-from", # TRY200 + # "redefined-builtin", # A001, ruff is way more stricter, needs work + "try-except-raise", # TRY302 + "unused-argument", # ARG001, we don't use it + "unused-format-string-argument", #F507 + "unused-format-string-key", # F504 + "unused-import", # F401 + "unused-variable", # F841 + "useless-else-on-loop", # PLW0120 + "wildcard-import", # F403 + "bad-classmethod-argument", # N804 + "consider-iterating-dictionary", # SIM118 + "empty-docstring", # D419 + "invalid-name", # N815 + "line-too-long", # E501, disabled globally + "missing-class-docstring", # D101 + "missing-final-newline", # W292 + "missing-function-docstring", # D103 + "missing-module-docstring", # D100 + "multiple-imports", #E401 + "singleton-comparison", # E711, E712 + "subprocess-run-check", # PLW1510 + "superfluous-parens", # UP034 + "ungrouped-imports", # I001 + "unidiomatic-typecheck", # E721 + "unnecessary-direct-lambda-call", # PLC3002 + "unnecessary-lambda-assignment", # PLC3001 + "unneeded-not", # SIM208 + "useless-import-alias", # PLC0414 + "wrong-import-order", # I001 + "wrong-import-position", # E402 + "comparison-of-constants", # PLR0133 + "comparison-with-itself", # PLR0124 + # "consider-alternative-union-syntax", # UP007 + "consider-merging-isinstance", # PLR1701 + # "consider-using-alias", # UP006 + "consider-using-dict-comprehension", # C402 + "consider-using-generator", # C417 + "consider-using-get", # SIM401 + "consider-using-set-comprehension", # C401 + "consider-using-sys-exit", # PLR1722 + "consider-using-ternary", # SIM108 + "literal-comparison", # F632 + "property-with-parameters", # PLR0206 + "super-with-arguments", # UP008 + "too-many-branches", # PLR0912 + "too-many-return-statements", # PLR0911 + "too-many-statements", # PLR0915 + "trailing-comma-tuple", # COM818 + "unnecessary-comprehension", # C416 + "use-a-generator", # C417 + "use-dict-literal", # C406 + "use-list-literal", # C405 + "useless-object-inheritance", # UP004 + "useless-return", # PLR1711 + # "no-self-use", # PLR6301 # Optional plugin, not enabled + + # Handled by mypy + # Ref: + "abstract-class-instantiated", + "arguments-differ", + "assigning-non-slot", + "assignment-from-no-return", + "assignment-from-none", + "bad-exception-cause", + "bad-format-character", + "bad-reversed-sequence", + "bad-super-call", + "bad-thread-instantiation", + "catching-non-exception", + "comparison-with-callable", + "deprecated-class", + "dict-iter-missing-items", + "format-combined-specification", + "global-variable-undefined", + "import-error", + "inconsistent-mro", + "inherit-non-class", + "init-is-generator", + "invalid-class-object", + "invalid-enum-extension", + "invalid-envvar-value", + "invalid-format-returned", + "invalid-hash-returned", + "invalid-metaclass", + "invalid-overridden-method", + "invalid-repr-returned", + "invalid-sequence-index", + "invalid-slice-index", + "invalid-slots-object", + "invalid-slots", + "invalid-star-assignment-target", + "invalid-str-returned", + "invalid-unary-operand-type", + "invalid-unicode-codec", + "isinstance-second-argument-not-valid-type", + "method-hidden", + "misplaced-format-function", + "missing-format-argument-key", + "missing-format-attribute", + "missing-kwoa", + "no-member", + "no-value-for-parameter", + "non-iterator-returned", + "non-str-assignment-to-dunder-name", + "nonlocal-and-global", + "not-a-mapping", + "not-an-iterable", + "not-async-context-manager", + "not-callable", + "not-context-manager", + "overridden-final-method", + "raising-bad-type", + "raising-non-exception", + "redundant-keyword-arg", + "relative-beyond-top-level", + "self-cls-assignment", + "signature-differs", + "star-needs-assignment-target", + "subclassed-final-class", + "super-without-brackets", + "too-many-function-args", + "typevar-double-variance", + "typevar-name-mismatch", + "unbalanced-dict-unpacking", + "unbalanced-tuple-unpacking", + "unexpected-keyword-arg", + "unhashable-member", + "unpacking-non-sequence", + "unsubscriptable-object", + "unsupported-assignment-operation", + "unsupported-binary-operation", + "unsupported-delete-operation", + "unsupported-membership-test", + "used-before-assignment", + "using-final-decorator-in-unsupported-version", + "wrong-exception-operation", +] +enable = [ + #"useless-suppression", # temporarily every now and then to clean them up + "use-symbolic-message-instead", +] + +[tool.pytest.ini_options] +asyncio_mode = "auto" + +[tool.ruff] +required-version = ">=0.4.1" +exclude = [".devcontainer", ".github", ".vscode", ".config"] + +[tool.ruff.lint] +select = [ + "A001", # Variable {name} is shadowing a Python builtin + "B002", # Python does not support the unary prefix increment + "B005", # Using .strip() with multi-character strings is misleading + "B007", # Loop control variable {name} not used within loop body + "B014", # Exception handler with duplicate exception + "B015", # Pointless comparison. Did you mean to assign a value? Otherwise, prepend assert or remove it. + "B017", # pytest.raises(BaseException) should be considered evil + "B018", # Found useless attribute access. Either assign it to a variable or remove it. + "B023", # Function definition does not bind loop variable {name} + "B026", # Star-arg unpacking after a keyword argument is strongly discouraged + "B032", # Possible unintentional type annotation (using :). Did you mean to assign (using =)? + "B904", # Use raise from to specify exception cause + "B905", # zip() without an explicit strict= parameter + "C", # complexity + "COM818", # Trailing comma on bare tuple prohibited + "D", # docstrings + "DTZ003", # Use datetime.now(tz=) instead of datetime.utcnow() + "DTZ004", # Use datetime.fromtimestamp(ts, tz=) instead of datetime.utcfromtimestamp(ts) + "E", # pycodestyle + "F", # pyflakes/autoflake + "FLY", # flynt + "G", # flake8-logging-format + "I", # isort + "INP", # flake8-no-pep420 + "ISC", # flake8-implicit-str-concat + "ICN001", # import concentions; {name} should be imported as {asname} + "LOG", # flake8-logging + "N804", # First argument of a class method should be named cls + "N805", # First argument of a method should be named self + "N815", # Variable {name} in class scope should not be mixedCase + "PERF", # Perflint + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "PYI", # flake8-pyi + "RET", # flake8-return + "RSE", # flake8-raise + "RUF005", # Consider iterable unpacking instead of concatenation + "RUF006", # Store a reference to the return value of asyncio.create_task + "RUF013", # PEP 484 prohibits implicit Optional + "RUF018", # Avoid assignment expressions in assert statements + "RUF019", # Unnecessary key check before dictionary access + # "RUF100", # Unused `noqa` directive; temporarily every now and then to clean them up + "S102", # Use of exec detected + "S103", # bad-file-permissions + "S108", # hardcoded-temp-file + "S306", # suspicious-mktemp-usage + "S307", # suspicious-eval-usage + "S313", # suspicious-xmlc-element-tree-usage + "S314", # suspicious-xml-element-tree-usage + "S315", # suspicious-xml-expat-reader-usage + "S316", # suspicious-xml-expat-builder-usage + "S317", # suspicious-xml-sax-usage + "S318", # suspicious-xml-mini-dom-usage + "S319", # suspicious-xml-pull-dom-usage + "S320", # suspicious-xmle-tree-usage + "S601", # paramiko-call + "S602", # subprocess-popen-with-shell-equals-true + "S604", # call-with-shell-equals-true + "S608", # hardcoded-sql-expression + "S609", # unix-command-wildcard-injection + "SIM", # flake8-simplify + "SLOT", # flake8-slots + "T100", # Trace found: {name} used + "T20", # flake8-print + "TID251", # Banned imports + "TRY", # tryceratops + "UP", # pyupgrade + "W", # pycodestyle +] + +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 + + "PLC1901", # {existing} can be simplified to {replacement} as an empty string is falsey; too many false positives + "PLR0911", # Too many return statements ({returns} > {max_returns}) + "PLR0912", # Too many branches ({branches} > {max_branches}) + "PLR0913", # Too many arguments to function call ({c_args} > {max_args}) + "PLR0915", # Too many statements ({statements} > {max_statements}) + "PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable + "PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target + "PT004", # Fixture {fixture} does not return anything, add leading underscore + "PT011", # pytest.raises({exception}) is too broad, set the `match` parameter or use a more specific exception + "PT012", # `pytest.raises()` block should contain a single simple statement + "PT018", # Assertion should be broken down into multiple parts + "RUF001", # String contains ambiguous unicode character. + "RUF002", # Docstring contains ambiguous unicode character. + "RUF003", # Comment contains ambiguous unicode character. + "RUF015", # Prefer next(...) over single element slice + "SIM102", # Use a single if statement instead of nested if statements + "SIM108", # Use ternary operator {contents} instead of if-else-block + "SIM115", # Use context handler for opening files + "TRY003", # Avoid specifying long messages outside the exception class + "TRY400", # Use `logging.exception` instead of `logging.error` + # Ignored due to performance: https://github.com/charliermarsh/ruff/issues/2923 + "UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)` + # Ignored due to incompatible with mypy: https://github.com/python/mypy/issues/15238 + "UP040", # Checks for use of TypeAlias annotation for declaring type aliases. + + # May conflict with the formatter, https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules + "W191", + "E111", + "E114", + "E117", + "D206", + "D300", + "Q", + "COM812", + "COM819", + "ISC001", + + # Disabled because ruff does not understand type of __all__ generated by a function + "PLE0605", + + # temporarily disabled + "PT019", + "PYI024", # Use typing.NamedTuple instead of collections.namedtuple + "RET503", + "RET502", + "RET501", + "TRY002", + "TRY301", +] + +[tool.ruff.lint.flake8-import-conventions.extend-aliases] +voluptuous = "vol" +"homeassistant.helpers.area_registry" = "ar" +"homeassistant.helpers.category_registry" = "cr" +"homeassistant.helpers.config_validation" = "cv" +"homeassistant.helpers.device_registry" = "dr" +"homeassistant.helpers.entity_registry" = "er" +"homeassistant.helpers.floor_registry" = "fr" +"homeassistant.helpers.issue_registry" = "ir" +"homeassistant.helpers.label_registry" = "lr" +"homeassistant.util.dt" = "dt_util" + +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false + +[tool.ruff.lint.flake8-tidy-imports.banned-api] +"async_timeout".msg = "use asyncio.timeout instead" +"pytz".msg = "use zoneinfo instead" + +[tool.ruff.lint.isort] +force-sort-within-sections = true +known-first-party = ["homeassistant"] +combine-as-imports = true +split-on-trailing-comma = false + +[tool.ruff.lint.per-file-ignores] + +# Allow for main entry & scripts to write to stdout +"homeassistant/__main__.py" = ["T201"] +"homeassistant/scripts/*" = ["T201"] +"script/*" = ["T20"] + +[tool.ruff.lint.mccabe] +max-complexity = 25 diff --git a/requirements_ha.txt b/requirements_ha.txt new file mode 100644 index 0000000..ee9b259 --- /dev/null +++ b/requirements_ha.txt @@ -0,0 +1,8 @@ +wheel +colorlog==6.8.2 +pip>=21.3.1 +ruff==0.5.1 +pre-commit==3.7.0 +zlib_ng +zeroconf +homeassistant From 1ffef21a026f99431e4a0c5a249f54621a4b2914 Mon Sep 17 00:00:00 2001 From: virtualdj Date: Sat, 10 Aug 2024 11:48:08 +0000 Subject: [PATCH 2/4] Errore logging --- config/configuration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/configuration.yaml b/config/configuration.yaml index 6cb01d0..a144e78 100644 --- a/config/configuration.yaml +++ b/config/configuration.yaml @@ -4,7 +4,7 @@ default_config: logger: default: info logs: - custom_components.pun_test: debug + custom_components.pun_sensor: debug # Disable ffmpeg ffmpeg: From 3ef853d6c78e273f35ee9c2982b6f135aa475bb1 Mon Sep 17 00:00:00 2001 From: virtualdj Date: Sat, 10 Aug 2024 12:00:14 +0000 Subject: [PATCH 3/4] Aggiornamento script minori ad uv --- .devcontainer/scripts/dev-branch | 2 +- .devcontainer/scripts/specific-version | 2 +- .devcontainer/scripts/upgrade | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.devcontainer/scripts/dev-branch b/.devcontainer/scripts/dev-branch index 942fd95..cb7d1c3 100755 --- a/.devcontainer/scripts/dev-branch +++ b/.devcontainer/scripts/dev-branch @@ -4,4 +4,4 @@ set -e cd "$(dirname "$0")/../.." -python3 -m pip --disable-pip-version-check install --upgrade git+https://github.com/home-assistant/home-assistant.git@dev +uv pip install --system --prefix "/home/vscode/.local/" --upgrade git+https://github.com/home-assistant/home-assistant.git@dev diff --git a/.devcontainer/scripts/specific-version b/.devcontainer/scripts/specific-version index 726b41a..9499dd9 100755 --- a/.devcontainer/scripts/specific-version +++ b/.devcontainer/scripts/specific-version @@ -5,4 +5,4 @@ set -e cd "$(dirname "$0")/../.." read -p 'Set Home Assistant version: ' -r version -python3 -m pip --disable-pip-version-check install --upgrade homeassistant=="$version" +uv pip install --system --prefix "/home/vscode/.local/" --upgrade homeassistant=="$version" diff --git a/.devcontainer/scripts/upgrade b/.devcontainer/scripts/upgrade index c87a647..8caebce 100755 --- a/.devcontainer/scripts/upgrade +++ b/.devcontainer/scripts/upgrade @@ -4,4 +4,4 @@ set -e cd "$(dirname "$0")/../.." -python3 -m pip install --upgrade --pre homeassistant +uv pip install --system --prefix "/home/vscode/.local/" --upgrade --prerelease allow homeassistant From 6e4b98307ed793f026ab560b2f6c365e13802fea Mon Sep 17 00:00:00 2001 From: virtualdj Date: Sat, 10 Aug 2024 12:02:55 +0000 Subject: [PATCH 4/4] Aggiornati link README --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3293752..5b24e4f 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Se la casella di controllo _Usa solo dati reali ad inizio mese_ è **attivata**, ### Aggiornamento manuale -È possibile forzare un **aggiornamento manuale** richiamando il servizio *Home Assistant Core Integration: Aggiorna entità* (`homeassistant.update_entity`) e passando come destinazione una qualsiasi entità tra quelle fornite da questa integrazione: questo causerà chiaramente un nuovo download dei dati. +È possibile forzare un **aggiornamento manuale** richiamando il servizio _Home Assistant Core Integration: Aggiorna entità_ (`homeassistant.update_entity`) e passando come destinazione una qualsiasi entità tra quelle fornite da questa integrazione: questo causerà chiaramente un nuovo download dei dati. ### Aspetto dei dati @@ -46,16 +46,16 @@ Di seguito un esempio di un sensore configurato manualmente modificando il file template: - sensor: - unique_id: prezzo_attuale_energia_al_dettaglio - name: 'Prezzo attuale energia al dettaglio' + name: "Prezzo attuale energia al dettaglio" icon: mdi:currency-eur - unit_of_measurement: '€/kWh' + unit_of_measurement: "€/kWh" state: > {{ (1.1 * (states('sensor.pun_prezzo_fascia_corrente')|float(0) + 0.0087 + 0.04 + 0.0227))|round(3) }} ``` ### Fascia F23 -A partire dalla versione v0.5.0, è stato aggiunto il sensore relativo al calcolo della fascia F23, cioè quella contrapposta alla F1 nella bioraria. Il calcolo non è documentato molto nei vari siti (si veda [QUI](https://github.com/virtualdj/pun_sensor/issues/24#issuecomment-1806864251)) e non è affatto la media dei prezzi in F2 e F3 come si potrebbe pensare: c'è invece una percentuale fissa, [come ha scoperto *virtualj*](https://github.com/virtualdj/pun_sensor/issues/24#issuecomment-1829846806). +A partire dalla versione v0.5.0, è stato aggiunto il sensore relativo al calcolo della fascia F23, cioè quella contrapposta alla F1 nella bioraria. Il calcolo non è documentato molto nei vari siti (si veda [QUI](https://github.com/virtualdj/pun_sensor/issues/24#issuecomment-1806864251)) e non è affatto la media dei prezzi in F2 e F3 come si potrebbe pensare: c'è invece una percentuale fissa, [come ha scoperto _virtualj_](https://github.com/virtualdj/pun_sensor/issues/24#issuecomment-1829846806). Pertanto, seppur questo metodo non sia ufficiale, è stato implementato perché i risultati corrispondono sempre alle tabelle pubblicate online. ### In caso di problemi @@ -92,4 +92,4 @@ Ovviamente non ho alcuna certezza che tutto questo sia la maniera giusta di proc - La [PR #99213](https://github.com/home-assistant/core/pull/99213/files) di Home Assistant per il suggerimento di usare `async_call_later` anziché sommare il timedelta all'ora corrente - La [PR #76793](https://github.com/home-assistant/core/pull/76793/files) di Home Assistant per un esempio di come usare il [cancellation token](https://developers.home-assistant.io/docs/integration_listen_events/#available-event-helpers) restituito da `async_track_point_in_time` - I commit [1](https://github.com/home-assistant/core/commit/c574d86ddbafd6c18995ad9efb297fda3ce4292c) e [2](https://github.com/home-assistant/core/commit/36e7689d139d0f517bbdd8f8f2c11e18936d27b3) per risolvere il warning nei log `[homeassistant.util.loop] Detected blocking call to import_module inside the event loop by custom integration` comparso con la versione 2024.5.0 di Home Assistant e dovuto alle librerie importate -- La configurazione del _devcontainer_ con script ispirati dalla repository [astrandb/viva](https://github.com/astrandb/viva/tree/main/scripts) e da post sulla [community Home Assistant](https://community.home-assistant.io/t/developing-home-assistant-core-in-a-vscode-devcontainer/235650/36) o sulla versione [francofona](https://www.hacf.fr/dev_tuto_1_environnement/) \ No newline at end of file +- La configurazione del _devcontainer_ con script ispirati dalla repository [astrandb/viva](https://github.com/astrandb/viva/tree/main/scripts) e da post sulla [community Home Assistant](https://community.home-assistant.io/t/developing-home-assistant-core-in-a-vscode-devcontainer/235650/36); utili anche [questo](https://www.hacf.fr/dev_tuto_1_environnement/) e [questo](https://svrooij.io/2023/01/18/home-assistant-component/)