Skip to content

Commit 40ea0e2

Browse files
authored
Merge pull request #62 from CoMPaTech/upd
Add pylint (generically) and force pytest Fix artifact upgrade (Github CI) Improve ip6 redaction
2 parents bbeded4 + 3bcfb57 commit 40ea0e2

File tree

11 files changed

+68
-16
lines changed

11 files changed

+68
-16
lines changed

.github/workflows/verify.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,15 @@ jobs:
145145
. venv/bin/activate
146146
uv pip install -r requirements.txt -r requirements-test.txt
147147
- name: Download all coverage artifacts
148-
uses: actions/download-artifact@v4
148+
uses: actions/download-artifact@v5
149+
with:
150+
pattern: coverage-*
151+
merge-multiple: true
152+
path: ${{ github.workspace }}/artifacts
149153
- name: Combine coverage results
150154
run: |
151155
. venv/bin/activate
152-
coverage combine coverage*/.coverage*
156+
coverage combine artifacts/.coverage*
153157
coverage report --fail-under=85
154158
coverage xml
155159
- name: Upload coverage to Codecov

.pre-commit-config.yaml

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ repos:
4949
- --quiet
5050
- --format=custom
5151
- --configfile=tests/bandit.yaml
52-
files: ^(airos|tests)/.+\.py$
52+
files: ^(airos|tests|script)/.+\.py$
5353
- repo: https://github.com/adrienverge/yamllint.git
5454
rev: v1.37.1
5555
hooks:
@@ -75,17 +75,30 @@ repos:
7575
- --py39-plus
7676
- --force
7777
- --keep-updates
78-
files: ^(airos|tests)/.+\.py$
78+
files: ^(airos|tests|script)/.+\.py$
7979
- repo: https://github.com/igorshubovych/markdownlint-cli
8080
rev: v0.45.0
8181
hooks:
8282
- id: markdownlint
8383
- repo: local
8484
hooks:
85+
- id: pytest
86+
name: "pytest"
87+
entry: script/run-in-env.sh pytest
88+
language: script
89+
types: [python]
90+
pass_filenames: false
91+
files: ^(airos|tests|script)/.+\.py$
92+
- id: pylint
93+
name: "pylinting"
94+
entry: script/run-in-env.sh pylint -j 0
95+
language: script
96+
types: [python]
97+
files: ^(airos|tests|script)/.+\.py$
8598
- id: mypy
8699
name: mypy
87100
entry: script/run-in-env.sh mypy
88101
language: script
89102
require_serial: true
90103
types_or: [python, pyi]
91-
files: ^(airos|tests|scripts)/.+\.(py|pyi)$
104+
files: ^(airos|tests|script)/.+\.(py|pyi)$

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [0.2.10] - 2025-08-13
6+
7+
### Changed
8+
9+
- Maintenance chores
10+
- Added pylint and pytest (and applicable changes)
11+
512
## [0.2.9] - 2025-08-12
613

714
### Changed

airos/airos8.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ async def login(self) -> bool:
193193
_LOGGER.info("Login task was cancelled")
194194
raise
195195

196-
def derived_data(self, response: dict[str, Any] = {}) -> dict[str, Any]:
196+
def derived_data(self, response: dict[str, Any]) -> dict[str, Any]:
197197
"""Add derived data to the device response."""
198198
derived: dict[str, Any] = {
199199
"station": False,

airos/data.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def _redact(d: dict[str, Any]) -> dict[str, Any]:
6161
for k, v in d.items():
6262
if k in sensitive_keys:
6363
if isinstance(v, str) and (is_mac_address(v) or is_mac_address_mask(v)):
64-
# Redact only the first 6 hex characters of a MAC address
64+
# Redact only the last part of a MAC address to a dummy value
6565
redacted_d[k] = "00:11:22:33:" + v.replace("-", ":").upper()[-5:]
6666
elif isinstance(v, str) and is_ip_address(v):
6767
# Redact to a dummy local IP address
@@ -71,6 +71,21 @@ def _redact(d: dict[str, Any]) -> dict[str, Any]:
7171
):
7272
# Redact list of IPs to a dummy list
7373
redacted_d[k] = ["127.0.0.3"] # type: ignore[assignment]
74+
elif isinstance(v, list) and all(
75+
isinstance(i, dict) and "addr" in i and is_ip_address(i["addr"])
76+
for i in v
77+
):
78+
# Redact list of dictionaries with IP addresses to a dummy list
79+
redacted_list = []
80+
for item in v:
81+
redacted_item = item.copy()
82+
redacted_item["addr"] = (
83+
"127.0.0.3"
84+
if ipaddress.ip_address(redacted_item["addr"]).version == 4
85+
else "::1"
86+
)
87+
redacted_list.append(redacted_item)
88+
redacted_d[k] = redacted_list # type: ignore[assignment]
7489
else:
7590
redacted_d[k] = "REDACTED"
7691
elif isinstance(v, dict):

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "airos"
7-
version = "0.2.9"
7+
version = "0.2.10"
88
license = "MIT"
99
description = "Ubiquity airOS module(s) for Python 3."
1010
readme = "README.md"

requirements-test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ aiofiles==24.1.0
99
radon==6.0.1
1010
types-aiofiles==24.1.0.20250809
1111
mypy==1.17.1
12+
pylint==3.3.7

script/generate_ha_fixture.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ def generate_airos_fixtures() -> None:
4242
_LOGGER.info("Processing '%s'...", filename)
4343

4444
try:
45-
with open(base_fixture_path) as source:
45+
with open(base_fixture_path, encoding="utf-8") as source:
4646
source_data = json.loads(source.read())
4747

4848
derived_data = AirOS.derived_data(None, source_data) # type: ignore[arg-type]
4949
new_data = AirOSData.from_dict(derived_data)
5050

51-
with open(new_fixture_path, "w") as new:
51+
with open(new_fixture_path, "w", encoding="utf-8") as new:
5252
json.dump(new_data.to_dict(), new, indent=2, sort_keys=True)
5353

5454
_LOGGER.info("Successfully created '%s'", new_filename)

script/mashumaro-step-debug.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
import sys
77
from typing import Any
88

9-
current_script_dir = os.path.dirname(os.path.abspath(__file__))
10-
project_root_dir = os.path.abspath(os.path.join(current_script_dir, os.pardir))
9+
_current_script_dir = os.path.dirname(os.path.abspath(__file__))
10+
_project_root_dir = os.path.abspath(os.path.join(_current_script_dir, os.pardir))
1111

12-
if project_root_dir not in sys.path:
13-
sys.path.append(project_root_dir)
12+
if _project_root_dir not in sys.path:
13+
sys.path.append(_project_root_dir)
1414

15-
from airos.data import AirOS8Data, Remote, Station, Wireless # noqa: E402
15+
from airos.data import AirOS8Data, Interface, Remote, Station, Wireless # noqa: E402
1616

1717
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
1818
_LOGGER = logging.getLogger(__name__)
@@ -31,7 +31,7 @@ def main() -> None:
3131
sys.path.append(project_root_dir)
3232

3333
# Load the JSON data
34-
with open(sys.argv[1]) as f:
34+
with open(sys.argv[1], encoding="utf-8") as f:
3535
data = json.loads(f.read())
3636

3737
try:
@@ -63,6 +63,14 @@ def main() -> None:
6363
wireless_obj = Wireless.from_dict(wireless_data) # noqa: F841
6464
_LOGGER.info(" -> Success! The Wireless object is valid.")
6565

66+
_LOGGER.info(" -> Checking list of Interface objects...")
67+
interfaces = data["interfaces"]
68+
for i, interface_data in enumerate(interfaces):
69+
_LOGGER.info(" -> Checking Interface object at index %s...", i)
70+
_LOGGER.info(" Interface should be %s.", interface_data["ifname"])
71+
interface_obj = Interface.from_dict(interface_data) # noqa: F841
72+
_LOGGER.info(" Success! Interface is valid.")
73+
6674
_LOGGER.info("Attempting to deserialize full AirOS8Data object...")
6775
airos_data_obj = AirOS8Data.from_dict(data) # noqa: F841
6876
_LOGGER.info("Success! Full AirOS8Data object is valid.")

tests/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import aiohttp
1212

13+
# pylint: disable=redefined-outer-name, unnecessary-default-type-args
14+
1315

1416
@pytest.fixture
1517
def base_url() -> str:

0 commit comments

Comments
 (0)