Repository: XKNX/xknx
Pull request #1548 (2024-08-19 10:50:24)

Bump ruff from 0.5.7 to 0.6.1
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.5.7 to 0.6.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/astral-sh/ruff/releases">ruff's releases</a>.</em></p>
<blockquote>
<h2>0.6.1</h2>
<h2>Release Notes</h2>
<p>This is a hotfix release to address an issue with <code>ruff-pre-commit</code>. In v0.6, Ruff changed its behavior to lint and format Jupyter notebooks by default; however, due to an oversight, these files were still excluded by default if Ruff was run via pre-commit, leading to inconsistent behavior. This has <a href="https://redirect.github.com/astral-sh/ruff-pre-commit/pull/96">now been fixed</a>.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>fastapi</code>] Implement <code>fast-api-unused-path-parameter</code> (<code>FAST003</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/12638">#12638</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>pylint</code>] Rename <code>too-many-positional</code> to <code>too-many-positional-arguments</code> (<code>R0917</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/12905">#12905</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Fix crash when applying &quot;fix-all&quot; code-action to notebook cells (<a href="https://redirect.github.com/astral-sh/ruff/pull/12929">#12929</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>[<code>flake8-naming</code>]: Respect import conventions (<code>N817</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/12922">#12922</a>)</li>
</ul>
<h2>Contributors</h2>
<ul>
<li><a href="https://github.com/AlexWaygood"><code>@​AlexWaygood</code></a></li>
<li><a href="https://github.com/JonathanPlasse"><code>@​JonathanPlasse</code></a></li>
<li><a href="https://github.com/Matthieu-LAURENT39"><code>@​Matthieu-LAURENT39</code></a></li>
<li><a href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a href="https://github.com/carljm"><code>@​carljm</code></a></li>
<li><a href="https://github.com/dhruvmanila"><code>@​dhruvmanila</code></a></li>
</ul>
<h2>Install ruff 0.6.1</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/ruff/releases/download/0.6.1/ruff-installer.sh | sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -c &quot;irm https://github.com/astral-sh/ruff/releases/download/0.6.1/ruff-installer.ps1 | iex&quot;
</code></pre>
<h2>Download ruff 0.6.1</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://github.com/astral-sh/ruff/releases/download/0.6.1/ruff-aarch64-apple-darwin.tar.gz">ruff-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a href="https://github.com/astral-sh/ruff/releases/download/0.6.1/ruff-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a href="https://github.com/astral-sh/ruff/releases/download/0.6.1/ruff-x86_64-apple-darwin.tar.gz">ruff-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a href="https://github.com/astral-sh/ruff/releases/download/0.6.1/ruff-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's changelog</a>.</em></p>
<blockquote>
<h2>0.6.1</h2>
<p>This is a hotfix release to address an issue with <code>ruff-pre-commit</code>. In v0.6,
Ruff changed its behavior to lint and format Jupyter notebooks by default;
however, due to an oversight, these files were still excluded by default if
Ruff was run via pre-commit, leading to inconsistent behavior.
This has <a href="https://redirect.github.com/astral-sh/ruff-pre-commit/pull/96">now been fixed</a>.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>fastapi</code>] Implement <code>fast-api-unused-path-parameter</code> (<code>FAST003</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/12638">#12638</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>[<code>pylint</code>] Rename <code>too-many-positional</code> to <code>too-many-positional-arguments</code> (<code>R0917</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/12905">#12905</a>)</li>
</ul>
<h3>Server</h3>
<ul>
<li>Fix crash when applying &quot;fix-all&quot; code-action to notebook cells (<a href="https://redirect.github.com/astral-sh/ruff/pull/12929">#12929</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>[<code>flake8-naming</code>]: Respect import conventions (<code>N817</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/12922">#12922</a>)</li>
</ul>
<h2>0.6.0</h2>
<p>Check out the <a href="https://astral.sh/blog/ruff-v0.6.0">blog post</a> for a migration guide and overview of the changes!</p>
<h3>Breaking changes</h3>
<p>See also, the &quot;Remapped rules&quot; section which may result in disabled rules.</p>
<ul>
<li>Lint and format Jupyter Notebook by default (<a href="https://redirect.github.com/astral-sh/ruff/pull/12878">#12878</a>).</li>
<li>Detect imports in <code>src</code> layouts by default for <code>isort</code> rules (<a href="https://redirect.github.com/astral-sh/ruff/pull/12848">#12848</a>)</li>
<li>The pytest rules <code>PT001</code> and <code>PT023</code> now default to omitting the decorator parentheses when there are no arguments (<a href="https://redirect.github.com/astral-sh/ruff/pull/12838">#12838</a>).</li>
</ul>
<h3>Deprecations</h3>
<p>The following rules are now deprecated:</p>
<ul>
<li><a href="https://docs.astral.sh/ruff/rules/pytest-missing-fixture-name-underscore/"><code>pytest-missing-fixture-name-underscore</code></a> (<code>PT004</code>)</li>
<li><a href="https://docs.astral.sh/ruff/rules/pytest-incorrect-fixture-name-underscore/"><code>pytest-incorrect-fixture-name-underscore</code></a> (<code>PT005</code>)</li>
<li><a href="https://docs.astral.sh/ruff/rules/unpacked-list-comprehension/"><code>unpacked-list-comprehension</code></a> (<code>UP027</code>)</li>
</ul>
<h3>Remapped rules</h3>
<p>The following rules have been remapped to new rule codes:</p>
<ul>
<li><a href="https://docs.astral.sh/ruff/rules/unnecessary-dict-comprehension-for-iterable/"><code>unnecessary-dict-comprehension-for-iterable</code></a>: <code>RUF025</code> to <code>C420</code></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/astral-sh/ruff/commit/499c0bd875c3f53c65f542a217b4d9a0962191c3"><code>499c0bd</code></a> Bump version to 0.6.1 (<a href="https://redirect.github.com/astral-sh/ruff/issues/12937">#12937</a>)</li>
<li><a href="https://github.com/astral-sh/ruff/commit/4cb30b598f4247970f714021616583549d0b8b1e"><code>4cb30b5</code></a> <code>N817</code> docs: refer to the correct setting (<a href="https://redirect.github.com/astral-sh/ruff/issues/12935">#12935</a>)</li>
<li><a href="https://github.com/astral-sh/ruff/commit/aba0d83c1138ba2a787aa80495c136a057014c52"><code>aba0d83</code></a> [<code>flake8-naming</code>]: Respect import conventions (<code>N817</code>) (<a href="https://redirect.github.com/astral-sh/ruff/issues/12922">#12922</a>)</li>
<li><a href="https://github.com/astral-sh/ruff/commit/c319414e54d03b64335c75e2df58bb3a0cd25e7e"><code>c319414</code></a> Ignore blank line rules for docs formatting (<a href="https://redirect.github.com/astral-sh/ruff/issues/12934">#12934</a>)</li>
<li><a href="https://github.com/astral-sh/ruff/commit/ef1f6d98a05526ba3c82dfb6d1004d85f322e0c8"><code>ef1f6d9</code></a> Fix description of where the contributor list comes from in instructions for ...</li>
<li><a href="https://github.com/astral-sh/ruff/commit/b850b812de0a1f2cfdd8a132ad1f069a1da7ce87"><code>b850b81</code></a> Use cell source code instead of the concatenated one (<a href="https://redirect.github.com/astral-sh/ruff/issues/12929">#12929</a>)</li>
<li><a href="https://github.com/astral-sh/ruff/commit/a87b27c0753b50653d658a533d19f7a3a9cc5ba6"><code>a87b27c</code></a> [red-knot] Add support for relative imports (<a href="https://redirect.github.com/astral-sh/ruff/issues/12910">#12910</a>)</li>
<li><a href="https://github.com/astral-sh/ruff/commit/9b73532b112b5c2aa9f820bcfc1185d7af6ca02d"><code>9b73532</code></a> [<code>flake8-async</code>] Fix examples to use <code>async with</code> (<a href="https://redirect.github.com/astral-sh/ruff/issues/12924">#12924</a>)</li>
<li><a href="https://github.com/astral-sh/ruff/commit/d8debb7a36bad602b543a299f5cdca5b4c29524f"><code>d8debb7</code></a> Simplify logic for <code>RUF027</code> (<a href="https://redirect.github.com/astral-sh/ruff/issues/12907">#12907</a>)</li>
<li><a href="https://github.com/astral-sh/ruff/commit/bd4a947b29564fdbe95a4ee6a188163cd2346eb7"><code>bd4a947</code></a> [red-knot] Add symbol and definition for parameters (<a href="https://redirect.github.com/astral-sh/ruff/issues/12862">#12862</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/astral-sh/ruff/compare/0.5.7...0.6.1">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ruff&package-manager=pip&previous-version=0.5.7&new-version=0.6.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 975e2a67..5928e5eb 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -8,7 +8,7 @@ repos:
           - tomli
         exclude_types: [csv, json]
   - repo: https://github.com/charliermarsh/ruff-pre-commit
-    rev: 'v0.5.7'
+    rev: 'v0.6.1'
     hooks:
       - id: ruff
         # in CI it is directly run by tox to allow dependency upgrade checks
diff --git a/docs/changelog.md b/docs/changelog.md
index 329685b3..1c9cf927 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -6,6 +6,10 @@ nav_order: 2
 
 # Changelog
 
+### DPT
+
+- Fix DPTHVACStatus inverted bit order
+
 # 3.1.0 DPT 1 2024-08-13
 
 ### DPT
diff --git a/xknx/dpt/dpt_20.py b/xknx/dpt/dpt_20.py
index aff5158b..f6ed63e4 100644
--- a/xknx/dpt/dpt_20.py
+++ b/xknx/dpt/dpt_20.py
@@ -158,23 +158,23 @@ class DPTHVACStatus(DPTComplex[HVACStatus]):
         raw = cls.validate_payload(payload)[0]
 
         mode: HVACOperationMode
-        if raw & 0b10000000:
+        if raw & 0x1:
             mode = HVACOperationMode.COMFORT
-        elif raw & 0b01000000:
+        elif raw & 0x2:
             mode = HVACOperationMode.STANDBY
-        elif raw & 0b00100000:
+        elif raw & 0x4:
             mode = HVACOperationMode.ECONOMY
-        elif raw & 0b00010000:
+        elif raw & 0x8:
             mode = HVACOperationMode.BUILDING_PROTECTION
         else:
             mode = HVACOperationMode.AUTO  # not sure if this is possible / valid
 
         return HVACStatus(
             mode=mode,
-            dew_point=bool(raw & 0b00001000),
-            heat_cool=HeatCool.HEAT if raw & 0b00000100 else HeatCool.COOL,
-            inactive=bool(raw & 0b00000010),
-            frost_alarm=bool(raw & 0b00000001),
+            dew_point=bool(raw & 0x10),
+            heat_cool=HeatCool.HEAT if raw & 0x20 else HeatCool.COOL,
+            inactive=bool(raw & 0x40),
+            frost_alarm=bool(raw & 0x80),
         )
 
     @classmethod
@@ -182,19 +182,19 @@ class DPTHVACStatus(DPTComplex[HVACStatus]):
         """Serialize to KNX/IP raw data."""
         raw = 0
         if value.mode is HVACOperationMode.COMFORT:
-            raw |= 0b10000000
+            raw |= 0x1
         elif value.mode is HVACOperationMode.STANDBY:
-            raw |= 0b01000000
+            raw |= 0x2
         elif value.mode is HVACOperationMode.ECONOMY:
-            raw |= 0b00100000
+            raw |= 0x4
         elif value.mode is HVACOperationMode.BUILDING_PROTECTION:
-            raw |= 0b00010000
+            raw |= 0x8
         if value.dew_point:
-            raw |= 0b00001000
+            raw |= 0x10
         if value.heat_cool is HeatCool.HEAT:
-            raw |= 0b00000100
+            raw |= 0x20
         if value.inactive:
-            raw |= 0b00000010
+            raw |= 0x40
         if value.frost_alarm:
-            raw |= 0b00000001
+            raw |= 0x80
         return DPTArray(raw)
diff --git a/xknx/management/management.py b/xknx/management/management.py
index 1a29c0e8..08125b24 100644
--- a/xknx/management/management.py
+++ b/xknx/management/management.py
@@ -158,7 +158,8 @@ class BroadcastContext:
         self.queue: asyncio.Queue[Telegram] = asyncio.Queue()
 
     async def receive(
-        self, timeout: float | None = 3
+        self,
+        timeout: float | None = 3,  # noqa: ASYNC109
     ) -> AsyncGenerator[Telegram, None]:
         """Receive telegrams from the broadcast context."""
         try:
diff --git a/xknx/management/procedures.py b/xknx/management/procedures.py
index 4cb0a361..40ce5a89 100644
--- a/xknx/management/procedures.py
+++ b/xknx/management/procedures.py
@@ -79,7 +79,9 @@ async def nm_individual_address_check(
 
 
 async def nm_individual_address_read(
-    xknx: XKNX, timeout: float | None = 3, raise_if_multiple: bool = False
+    xknx: XKNX,
+    timeout: float | None = 3,  # noqa: ASYNC109
+    raise_if_multiple: bool = False,
 ) -> list[IndividualAddress]:
     """
     Request individual addresses of all devices that are in programming mode.
@@ -181,7 +183,9 @@ async def nm_invididual_address_write(
 
 
 async def nm_individual_address_serial_number_read(
-    xknx: XKNX, serial: bytes, timeout: float = 3
+    xknx: XKNX,
+    serial: bytes,
+    timeout: float = 3,  # noqa: ASYNC109
 ) -> IndividualAddress | None:
     """Read individual address from device with specified serial number."""
 


Test patch:
diff --git a/requirements/testing.txt b/requirements/testing.txt
index 72071eb3..884ee3b8 100644
--- a/requirements/testing.txt
+++ b/requirements/testing.txt
@@ -7,7 +7,7 @@ pytest==8.3.2
 pytest-asyncio==0.23.8
 pytest-cov==5.0.0
 pytest-icdiff==0.9
-ruff==0.5.7
+ruff==0.6.1
 setuptools==72.2.0
 tox==4.18.0
 tox-gh-actions==3.2.0
diff --git a/test/conftest.py b/test/conftest.py
index 1ee1bc62..f8ddccb3 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -31,7 +31,7 @@ class EventLoopClockAdvancer:
 
     async def _exhaust_callbacks(self) -> None:
         """Run the loop until all ready callbacks are executed."""
-        while self.loop._ready:  # type: ignore[attr-defined]
+        while self.loop._ready:  # noqa: ASYNC110  # type: ignore[attr-defined]
             await asyncio.sleep(0)
 
     async def __call__(self, seconds: float) -> None:
diff --git a/test/devices_tests/climate_test.py b/test/devices_tests/climate_test.py
index 62004811..f4132c03 100644
--- a/test/devices_tests/climate_test.py
+++ b/test/devices_tests/climate_test.py
@@ -308,16 +308,19 @@ class TestClimate:
         climate_mode.process(
             Telegram(
                 destination_address=GroupAddress("1/2/4"),
-                payload=GroupValueWrite(DPTArray((0b10000000,))),
+                payload=GroupValueWrite(DPTArray((0x01,))),
             )
         )
+        assert climate_mode.controller_mode == HVACControllerMode.COOL
+        assert climate_mode.operation_mode == HVACOperationMode.COMFORT
+
         # controller mode
         await climate_mode.set_controller_mode(HVACControllerMode.HEAT)
         assert xknx.telegrams.qsize() == 1
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/4"),
-            payload=GroupValueWrite(DPTArray((0b10000100,))),
+            payload=GroupValueWrite(DPTArray((0x21,))),
         )
         climate_mode.process(telegram)  # process to have internal value updated
         # operation mode
@@ -326,7 +329,7 @@ class TestClimate:
         telegram = xknx.telegrams.get_nowait()
         assert telegram == Telegram(
             destination_address=GroupAddress("1/2/4"),
-            payload=GroupValueWrite(DPTArray((0b01000100,))),
+            payload=GroupValueWrite(DPTArray((0x22,))),
         )
 
     async def test_set_operation_mode_with_separate_addresses(self):
diff --git a/test/dpt_tests/dpt_20_hvac_mode_test.py b/test/dpt_tests/dpt_20_hvac_mode_test.py
index aa12220b..096836a8 100644
--- a/test/dpt_tests/dpt_20_hvac_mode_test.py
+++ b/test/dpt_tests/dpt_20_hvac_mode_test.py
@@ -202,7 +202,7 @@ class TestDPTHVACStatus:
                     inactive=False,
                     frost_alarm=False,
                 ),
-                (0b10000100,),
+                (0x21,),
             ),
             (
                 HVACStatus(
@@ -212,8 +212,8 @@ class TestDPTHVACStatus:
                     inactive=False,
                     frost_alarm=False,
                 ),
-                (0b10000000,),
-            ),  # min values
+                (0x01,),
+            ),
             (
                 HVACStatus(
                     mode=HVACOperationMode.ECONOMY,
@@ -222,7 +222,7 @@ class TestDPTHVACStatus:
                     inactive=False,
                     frost_alarm=True,
                 ),
-                (0b00101001,),
+                (0x94,),
             ),
         ],
     )
@@ -243,7 +243,7 @@ class TestDPTHVACStatus:
                     "inactive": False,
                     "frost_alarm": False,
                 },
-                (0b10000100,),
+                (0x21,),
             ),
             (
                 {
@@ -253,7 +253,7 @@ class TestDPTHVACStatus:
                     "inactive": True,
                     "frost_alarm": False,
                 },
-                (0b01000010,),
+                (0x42,),
             ),
         ],
     )