Skip to content

Commit

Permalink
Merge pull request #941 from puddly/rc
Browse files Browse the repository at this point in the history
0.44.0 Release
  • Loading branch information
puddly committed Mar 30, 2022
2 parents cbd3b91 + 997cefd commit f5dc026
Show file tree
Hide file tree
Showing 55 changed files with 4,276 additions and 1,934 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,50 @@ jobs:
. venv/bin/activate
pre-commit run --hook-stage manual codespell --all-files --show-diff-on-failure
lint-mypy:
name: Check mypy
runs-on: ubuntu-latest
needs: pre-commit
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.4
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache@v2
with:
path: venv
key: >-
${{ env.CACHE_VERSION}}-${{ runner.os }}-base-venv-${{
steps.python.outputs.python-version }}-${{
hashFiles('requirements_test.txt') }}
- name: Fail job if Python cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
echo "Failed to restore Python virtual environment from cache"
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v2
with:
path: ${{ env.PRE_COMMIT_HOME }}
key: |
${{ env.CACHE_VERSION}}-${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Fail job if cache restore failed
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
echo "Failed to restore Python virtual environment from cache"
exit 1
- name: Run mypy
run: |
. venv/bin/activate
pre-commit run --hook-stage manual mypy --all-files --show-diff-on-failure
pytest:
runs-on: ubuntu-latest
needs: prepare-base
Expand Down
27 changes: 19 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v2.31.1
hooks:
- id: pyupgrade

- repo: https://github.com/fsouza/autoflake8
rev: v0.3.2
hooks:
- id: autoflake8

- repo: https://github.com/psf/black
rev: 20.8b1
rev: 22.3.0
hooks:
- id: black
args:
- --safe
- --quiet

- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.4
rev: 4.0.1
hooks:
- id: flake8

- repo: https://github.com/PyCQA/isort
rev: 5.5.2
rev: 5.10.1
hooks:
- id: isort

- repo: https://github.com/codespell-project/codespell
rev: v1.17.1
rev: v2.1.0
hooks:
- id: codespell
args:
- --ignore-words-list=ser,nd,hass
- --skip="./.*"
- --quiet-level=2

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.942
hooks:
- id: mypy
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Reference implementation of the zigpy library exist in **[Home Assistant](https:

zigpy have code to automatically download and perform OTA (Over-The-Air) firmware updates of Zigbee devices if the OTA firmware image provider source URL for updates is known. The OTA update directory is optional and it can also be used for any offline firmware files that you provide yourself.

Online OTA providers for firmware updates are currently only available for IKEA, LEDVANCE and SALUS devices. Support for OTA updates from other manufacturers could be added to zigpy in the future, if they publish their firmware images publicly.
Online OTA providers for firmware updates are currently only available for IKEA, LEDVANCE/OSRAM, and SALUS/Computime devices. Support for OTA updates from other manufacturers could be added to zigpy in the future, if they publish their firmware images publicly.

## How to install and test, report bugs, or contribute to this project

Expand Down
39 changes: 38 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[pyupgrade]
py37plus = True

[autoflake8]
in-place = True
recursive = False
expand-star-imports = False
exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build

[flake8]
exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build
# To work with Black
Expand All @@ -7,7 +16,7 @@ max-line-length = 88
# E501: line too long
# W503: Line break occurred before a binary operator
ignore =
D202,
# D202,
E203,
E501,
W503
Expand All @@ -19,3 +28,31 @@ force_sort_within_sections = true
known_first_party = zigpy,tests
forced_separate = tests
combine_as_imports = true

[codespell]
ignore-words-list = ser,nd,hass
skip = ./.*,test/*
quiet-level = 2

[mypy]
ignore_missing_imports = True
install_types = True
non_interactive = True
show_error_codes = True
show_error_context = True
error_summary = True
disable_error_code =
# Only a few notifications left:
type-arg,
# Only a few notifications left:
return-value,
# operator breaks in CI (zigpy.types.basic), but not locally
operator,
valid-type,
misc,
dict-item,
attr-defined,
assignment,
arg-type
# Only report on selected files
follow_imports = silent
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
license="GPL-3.0",
packages=find_packages(exclude=["tests", "tests.*"]),
install_requires=REQUIRES,
python_requires=">=3.7",
package_data={"": ["appdb_schemas/schema_v*.sql"]},
)
2 changes: 1 addition & 1 deletion tests/test_app_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def test_counters_init():
counters[name]
assert len(counters) == 3

cnt_1, cnt_2, cnt_3 = [counter for counter in counters.counters()]
cnt_1, cnt_2, cnt_3 = (counter for counter in counters.counters())
assert cnt_1.name == "counter_1"
assert cnt_2.name == "counter_2"
assert cnt_3.name == "some random name"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_appdb_pysqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def force_use_pysqlite3():

# Re-run most of the appdb tests
from tests.test_appdb import * # noqa: F401,F403
from tests.test_appdb_migration import * # noqa: F401,F403
from tests.test_appdb_migration import * # type:ignore[no-redef] # noqa: F401,F403

del test_pysqlite_load_success # noqa: F821
del test_pysqlite_load_failure # noqa: F821
2 changes: 1 addition & 1 deletion tests/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ async def test_known_device_left(app, ieee):
async def _remove(
app, ieee, retval, zdo_reply=True, delivery_failure=True, has_node_desc=True
):
async def leave():
async def leave(*args, **kwargs):
if zdo_reply:
return retval
elif delivery_failure:
Expand Down
79 changes: 79 additions & 0 deletions tests/test_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,78 @@ async def test_handle_message(dev):
assert ep.handle_message.call_count == 1


async def test_handle_message_read_report_conf(dev):
ep = dev.add_endpoint(3)
ep.add_input_cluster(0x702)
tsn = 0x56
req_mock = MagicMock()
dev._pending[tsn] = req_mock

# Read Report Configuration Success
rsp = dev.handle_message(
0x104, # profile
0x702, # cluster
3, # source EP
3, # dest EP
b"\x18\x56\x09\x00\x00\x00\x00\x25\x1e\x00\x84\x03\x01\x02\x03\x04\x05\x06", # message
)
# Returns decoded msg when response is not pending, None otherwise
assert rsp is None
assert req_mock.result.set_result.call_count == 1
cfg_sup1 = req_mock.result.set_result.call_args[0][0].attribute_configs[0]
assert isinstance(cfg_sup1, zigpy.zcl.foundation.AttributeReportingConfigWithStatus)
assert cfg_sup1.status == zigpy.zcl.foundation.Status.SUCCESS
assert cfg_sup1.config.direction == 0
assert cfg_sup1.config.attrid == 0
assert cfg_sup1.config.datatype == 0x25
assert cfg_sup1.config.min_interval == 30
assert cfg_sup1.config.max_interval == 900
assert cfg_sup1.config.reportable_change == 0x060504030201

# Unsupported attributes
tsn2 = 0x5B
req_mock2 = MagicMock()
dev._pending[tsn2] = req_mock2
rsp2 = dev.handle_message(
0x104, # profile
0x702, # cluster
3, # source EP
3, # dest EP
b"\x18\x5b\x09\x86\x00\x00\x00\x86\x00\x12\x00\x86\x00\x00\x04", # message 3x("Unsupported attribute" response)
)
# Returns decoded msg when response is not pending, None otherwise
assert rsp2 is None
cfg_unsup1, cfg_unsup2, cfg_unsup3 = req_mock2.result.set_result.call_args[0][
0
].attribute_configs
assert (
cfg_unsup1.status
== cfg_unsup2.status
== cfg_unsup3.status
== zigpy.zcl.foundation.Status.UNSUPPORTED_ATTRIBUTE
)
assert cfg_unsup1.config.direction == 0x00 and cfg_unsup1.config.attrid == 0x0000
assert cfg_unsup2.config.direction == 0x00 and cfg_unsup2.config.attrid == 0x0012
assert cfg_unsup3.config.direction == 0x00 and cfg_unsup3.config.attrid == 0x0400

# One supported, one unsupported
tsn3 = 0x5C
req_mock3 = MagicMock()
dev._pending[tsn3] = req_mock3
rsp3 = dev.handle_message(
0x104, # profile
0x702, # cluster
3, # source EP
3, # dest EP
b"\x18\x5c\x09\x86\x00\x00\x00\x00\x00\x00\x00\x25\x1e\x00\x84\x03\x01\x02\x03\x04\x05\x06",
)
assert rsp3 is None
cfg_unsup4, cfg_sup2 = req_mock3.result.set_result.call_args[0][0].attribute_configs
assert cfg_unsup4.status == zigpy.zcl.foundation.Status.UNSUPPORTED_ATTRIBUTE
assert cfg_sup2.status == zigpy.zcl.foundation.Status.SUCCESS
assert cfg_sup2.serialize() == cfg_sup1.serialize()


async def test_handle_message_reply(dev):
ep = dev.add_endpoint(3)
ep.handle_message = MagicMock()
Expand Down Expand Up @@ -335,3 +407,10 @@ def test_device_manufacture_id_override(dev):

dev.node_desc = None
assert dev.manufacturer_id == 2345


def test_device_name(dev):
"""Test device name property."""

assert dev.nwk == 0xFFFF
assert dev.name == "0xFFFF"
Loading

0 comments on commit f5dc026

Please sign in to comment.