diff --git a/.devcontainer.json b/.devcontainer.json new file mode 100644 index 0000000..4737fb0 --- /dev/null +++ b/.devcontainer.json @@ -0,0 +1,55 @@ +{ + "name": "astrandb/dev-viva", + "image": "mcr.microsoft.com/vscode/devcontainers/python:0-3.11-bullseye", + "postCreateCommand": "scripts/setup", + "appPort": ["9124:8123"], + "portsAttributes": { + "8123": { + "label": "Home Assistant internal", + "onAutoForward": "notify" + }, + "9124": { + "label": "Home Assistant remote", + "onAutoForward": "notify" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python", + "github.vscode-pull-request-github", + "ryanluker.vscode-coverage-gutters", + "ms-python.vscode-pylance", + "ms-python.pylint", + "ms-python.black-formatter", + "thibault-vanderseypen.i18n-json-editor" + ], + "settings": { + "files.eol": "\n", + "editor.tabSize": 4, + "python.pythonPath": "/usr/bin/python3", + "python.analysis.autoSearchPaths": false, + "python.linting.pylintEnabled": true, + "python.linting.enabled": true, + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.formatOnSave": true + }, + "python.formatting.provider": "none", + "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": {} + } +} diff --git a/.devcontainer/configuration.yaml b/.devcontainer/configuration.yaml deleted file mode 100644 index f2c5eba..0000000 --- a/.devcontainer/configuration.yaml +++ /dev/null @@ -1,9 +0,0 @@ -default_config: - -logger: - default: info - logs: - custom_components.viva: debug - -# If you need to debug uncomment the line below (doc: https://www.home-assistant.io/integrations/debugpy/) -debugpy: diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index a17e1b3..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,48 +0,0 @@ -// See https://aka.ms/vscode-remote/devcontainer.json for format details. -{ - "image": "ghcr.io/ludeeus/devcontainer/integration:stable", - "name": "Viva integration", - "context": "..", - "appPort": [ - "9124:8123" - ], - "postCreateCommand": "container install && pip install -Ur requirements-devcontainer.txt && pre-commit install", - "customizations": { - "vscode": { - "extensions": [ - "ms-python.python", - "github.vscode-pull-request-github", - "ryanluker.vscode-coverage-gutters", - "ms-python.vscode-pylance" - ], - "settings": { - "files.eol": "\n", - "editor.tabSize": 4, - "terminal.integrated.profiles.linux": { - "bash": { - "path": "bash", - "icon": "terminal-bash" - }, - "zsh": { - "path": "zsh" - } - }, - "terminal.integrated.defaultProfile.linux": "bash", - "python.pythonPath": "/usr/bin/python3", - "python.analysis.autoSearchPaths": false, - "python.linting.pylintEnabled": true, - "python.linting.enabled": true, - "python.formatting.provider": "black", - "editor.formatOnPaste": false, - "editor.formatOnSave": true, - "editor.formatOnType": true, - "files.trimTrailingWhitespace": true - } - } - }, - "mounts": [ - // Custom persistent configuration directory - // "source=${localEnv:HOME}/viva_config,target=${containerWorkspaceFolder}/config,type=bind" - "source=${localEnv:HOME}/viva_config,target=/config,type=bind" - ] -} diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..ff44256 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,15 @@ +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +version: 2 +updates: + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'weekly' + + - package-ecosystem: 'pip' + directory: '/' + schedule: + interval: 'weekly' + ignore: + # Dependabot should not update Home Assistant as that should match the homeassistant key in hacs.json + - dependency-name: 'homeassistant' diff --git a/.gitignore b/.gitignore index b6e4761..f56ca57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# Home Assistant confis +config/* +!config/configuration.yaml + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ea181c6..1835e15 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,30 +1,34 @@ repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.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 - - id: check-added-large-files -- repo: https://github.com/psf/black - rev: 23.1.0 - hooks: - - id: black - args: - - --quiet - files: ^((custom_components|homeassistant|pylint|script|tests)/.+)?[^/]+\.py$ -- repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.278 + hooks: + - id: ruff + args: + - --fix + - repo: https://github.com/psf/black + rev: 23.1.0 + hooks: + - id: black + args: + - --quiet + files: ^((custom_components|homeassistant|pylint|script|tests)/.+)?[^/]+\.py$ + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.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/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..72142bd --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,100 @@ +# The contents of this file is based on https://github.com/home-assistant/core/blob/dev/pyproject.toml + +target-version = "py310" + +select = [ + "B002", # Python does not support the unary prefix increment + "B007", # Loop control variable {name} not used within loop body + "B014", # Exception handler with duplicate exception + "B023", # Function definition does not bind loop variable {name} + "B026", # Star-arg unpacking after a keyword argument is strongly discouraged + "C", # complexity + "COM818", # Trailing comma on bare tuple prohibited + "D", # docstrings + "E", # pycodestyle + "F", # pyflakes/autoflake + "G", # flake8-logging-format + "I", # isort + "ICN001", # import concentions; {name} should be imported as {asname} + "ISC001", # Implicitly concatenated string literals on one line + "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 + "PGH001", # No builtin eval() allowed + "PGH004", # Use specific rule codes when using noqa + "PLC0414", # Useless import alias. Import alias does not rename original package. + "PLC", # pylint + "PLE", # pylint + "PLR", # pylint + "PLW", # pylint + "Q000", # Double quotes found but single quotes preferred + "RUF006", # Store a reference to the return value of asyncio.create_task + "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 + "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} + "SIM208", # Use {expr} instead of not (not {expr}) + "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 + "T100", # Trace found: {name} used + "T20", # flake8-print + "TRY004", # Prefer TypeError exception for invalid type + "TRY200", # Use raise from to specify exception cause + "TRY302", # Remove exception handler; error is immediately re-raised + "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 + "E731", # do not assign a lambda expression, use a def + "PLC1901", # Lots of false positives + # False positives https://github.com/astral-sh/ruff/issues/5386 + "PLC0208", # Use a sequence type instead of a `set` when iterating over values + "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 + "UP006", # keep type annotation style as is + "UP007", # keep type annotation style as is + # Ignored due to performance: https://github.com/charliermarsh/ruff/issues/2923 + "UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)` + +] + +[isort] +force-sort-within-sections = true +known-first-party = ["homeassistant"] +combine-as-imports = true + +[flake8-pytest-style] +fixture-parentheses = false + +[mccabe] +max-complexity = 25 diff --git a/.vscode/settings.json b/.vscode/settings.json index 0bd0e10..e69de29 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +0,0 @@ -{ - "python.linting.pylintEnabled": true, - "python.linting.enabled": true, - "python.pythonPath": "/usr/local/bin/python", - "files.associations": { - "*.yaml": "home-assistant" - } -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a1aacba..ec30a65 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,26 +4,20 @@ { "label": "Run Home Assistant on port 9124", "type": "shell", - "command": "container start", + "command": "scripts/develop", "problemMatcher": [] }, { - "label": "Run Home Assistant configuration against /config", + "label": "Upgrade Home Assistant to latest (beta)", "type": "shell", - "command": "container check", + "command": "scripts/upgrade", "problemMatcher": [] }, { - "label": "Upgrade Home Assistant to latest dev", + "label": "Lint with ruff", "type": "shell", - "command": "container install", - "problemMatcher": [] - }, - { - "label": "Install a specific version of Home Assistant", - "type": "shell", - "command": "container set-version", + "command": "scripts/lint", "problemMatcher": [] } ] -} +} diff --git a/Makefile b/Makefile index 0d71c5a..a6bee76 100644 --- a/Makefile +++ b/Makefile @@ -9,17 +9,17 @@ bump_minor: bump_major: bump2version --allow-dirty major $(src_dir)/const.py $(src_dir)/manifest.json -lint: - isort $(src_dir) - black $(src_dir) - flake8 $(src_dir) +# lint: +# isort $(src_dir) +# black $(src_dir) +# flake8 $(src_dir) -.venv: - python3.9 -m venv .venv +# .venv: +# python3.9 -m venv .venv -install_dev: | .venv - (. .venv/bin/activate; \ - pip install -Ur requirements-dev.txt ) +# install_dev: | .venv +# (. .venv/bin/activate; \ +# pip install -Ur requirements-dev.txt ) -clean: - rm -rf .venv $(src_dir)/__pycache__ +# clean: +# rm -rf .venv $(src_dir)/__pycache__ diff --git a/config/configuration.yaml b/config/configuration.yaml new file mode 100644 index 0000000..b09bbdf --- /dev/null +++ b/config/configuration.yaml @@ -0,0 +1,16 @@ + +# Loads default set of integrations. Do not remove. +default_config: + +# Load frontend themes from the themes folder +frontend: + themes: !include_dir_merge_named themes + +automation: !include automations.yaml +script: !include scripts.yaml +scene: !include scenes.yaml + +logger: + default: info + logs: + homeassistant.components.viva: debug diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 20b9302..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,2 +0,0 @@ --r requirements-devcontainer.txt -homeassistant diff --git a/requirements-devcontainer.txt b/requirements-devcontainer.txt deleted file mode 100644 index 6044e29..0000000 --- a/requirements-devcontainer.txt +++ /dev/null @@ -1,7 +0,0 @@ -black -bump2version -colorlog -flake8 -isort -wheel -pre-commit diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..21b933e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +colorlog==6.7.0 +homeassistant +pip>=21.0,<23.3 +ruff==0.0.278 +pre-commit==3.3.3 +bump2version==1.0.1 diff --git a/scripts/develop b/scripts/develop new file mode 100755 index 0000000..8d2c497 --- /dev/null +++ b/scripts/develop @@ -0,0 +1,29 @@ +#!/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 + + +# 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/scripts/lint b/scripts/lint new file mode 100755 index 0000000..9b5b1df --- /dev/null +++ b/scripts/lint @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +ruff check . --fix diff --git a/scripts/setup b/scripts/setup new file mode 100755 index 0000000..68a65c0 --- /dev/null +++ b/scripts/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +python3 -m pip install --requirement requirements.txt +pre-commit install diff --git a/scripts/upgrade b/scripts/upgrade new file mode 100755 index 0000000..7ce8f78 --- /dev/null +++ b/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/tests/fixtures/viva_sites.json b/tests/fixtures/viva_sites.json new file mode 100644 index 0000000..7137478 --- /dev/null +++ b/tests/fixtures/viva_sites.json @@ -0,0 +1,3 @@ +{ + "test": "test" +} diff --git a/tests/test_api.py b/tests/test_api.py new file mode 100644 index 0000000..c864b72 --- /dev/null +++ b/tests/test_api.py @@ -0,0 +1,4 @@ +"""Provide tests for viva api.""" + +# import pytest +# from tests.common import load_fixture