python-bsblan 6.1.5__tar.gz → 6.1.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/PKG-INFO +1 -1
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/pyproject.toml +2 -2
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/_transport.py +29 -1
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_bsblan_edge_cases.py +2 -2
- python_bsblan-6.1.6/tests/test_response_encoding.py +62 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.editorconfig +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.gitattributes +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/CODE_OF_CONDUCT.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/CONTRIBUTING.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/SECURITY.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/agents/pr-review.agent.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/agents/security-reviewer.agent.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/agents/tdd-refactor.agent.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/copilot-instructions.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/hooks/run-validation-after-edits.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/hooks/run_validation_after_edits.sh +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/labels.yml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/prompts/add-parameter.prompt.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/prompts/code-review.prompt.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/prompts/opsx-apply.prompt.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/prompts/opsx-archive.prompt.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/prompts/opsx-explore.prompt.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/prompts/opsx-propose.prompt.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/prompts/opsx-sync.prompt.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/release-drafter.yml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/renovate.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/skills/bsblan-parameters/SKILL.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/skills/bsblan-testing/SKILL.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/skills/feature-doc-updates/SKILL.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/skills/openspec-apply-change/SKILL.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/skills/openspec-archive-change/SKILL.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/skills/openspec-explore/SKILL.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/skills/openspec-propose/SKILL.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/skills/openspec-sync-specs/SKILL.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/auto-approve-renovate.yml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/codeql.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/dependency-review.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/docs.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/labels.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/linting.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/lock.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/pr-labels.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/release-drafter.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/release.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/scorecard.yml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/stale.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/tests.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/workflows/typing.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.github/zizmor.yml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.gitignore +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.nvmrc +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.pre-commit-config.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.prettierignore +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/.yamllint +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/AGENTS.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/CLAUDE.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/LICENSE.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/Makefile +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/README.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/docs/api/client.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/docs/api/constants.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/docs/api/exceptions.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/docs/api/models.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/docs/getting-started.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/docs/index.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/examples/control.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/examples/discovery.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/examples/fetch_param.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/examples/profile_init.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/examples/ruff.toml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/examples/speed_test.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/mkdocs.yml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-03-add-cooling-operating-mode/.openspec.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-03-add-cooling-operating-mode/design.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-03-add-cooling-operating-mode/proposal.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-03-add-cooling-operating-mode/specs/cooling-operating-mode/spec.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-03-add-cooling-operating-mode/tasks.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-harden-circuit-discovery-consistency/.openspec.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-harden-circuit-discovery-consistency/design.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-harden-circuit-discovery-consistency/proposal.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-harden-circuit-discovery-consistency/specs/circuit-discovery/spec.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-harden-circuit-discovery-consistency/tasks.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-improve-client-readability-domain-slices/.openspec.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-improve-client-readability-domain-slices/design.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-improve-client-readability-domain-slices/proposal.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-improve-client-readability-domain-slices/specs/client-retry-policy/spec.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/changes/archive/2026-07-04-improve-client-readability-domain-slices/tasks.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/config.yaml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/specs/circuit-discovery/spec.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/specs/client-retry-policy/spec.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/openspec/specs/cooling-operating-mode/spec.md +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/package-lock.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/package.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/sonar-project.properties +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/__init__.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/_hot_water.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/_parameters.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/_schedules.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/_temperature.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/_thermostat.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/_validation.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/_version.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/bsblan.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/constants.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/exceptions.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/models.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/py.typed +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/src/bsblan/utility.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/__init__.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/conftest.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/device.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/dict_version.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/hot_water_state.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/info.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/password.txt +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/pps_device.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/pps_state.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/pps_static_values.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/sensor.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/state.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/state_circuit2.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/static_state.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/static_state_circuit2.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/thermostat_hvac.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/thermostat_temp.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/fixtures/time.json +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/ruff.toml +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_api_initialization.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_api_validation.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_auth.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_backoff_retry.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_bsblan.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_circuit.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_configuration.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_constants.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_context_manager.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_device.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_dhw_time_switch.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_entity_info.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_entity_info_ha.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_heating_schedule.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_hot_water_additional.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_hotwater_state.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_include_parameter.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_info.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_initialization.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_pps.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_read_parameters.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_reset_validation.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_schedule_models.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_sensor.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_set_heating_schedule.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_set_hot_water_schedule.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_set_hotwater.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_state.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_static_state.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_temperature_unit.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_temperature_validation.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_thermostat.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_time.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_utility.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_utility_additional.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_utility_edge_cases.py +0 -0
- {python_bsblan-6.1.5 → python_bsblan-6.1.6}/tests/test_version_errors.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-bsblan"
|
|
3
|
-
version = "6.1.
|
|
3
|
+
version = "6.1.6"
|
|
4
4
|
description = "Asynchronous Python client for BSBLAN API"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Willem-Jan van Rootselaar", email = "liudgervr@gmail.com"}
|
|
@@ -196,7 +196,7 @@ dev = [
|
|
|
196
196
|
# hatch is required to support type hinting and proper packaging of the py.typed file.
|
|
197
197
|
"hatch>=1.14.1",
|
|
198
198
|
"isort==8.0.1",
|
|
199
|
-
"ty==0.0.
|
|
199
|
+
"ty==0.0.56",
|
|
200
200
|
"prek>=0.3.3",
|
|
201
201
|
"pre-commit-hooks==6.0.0",
|
|
202
202
|
"pylint==4.0.5",
|
|
@@ -9,6 +9,7 @@ stable ``_request`` facade that delegates here.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import asyncio
|
|
12
|
+
import json
|
|
12
13
|
import logging
|
|
13
14
|
from typing import TYPE_CHECKING, Any, cast
|
|
14
15
|
|
|
@@ -131,7 +132,7 @@ class BSBLANTransport:
|
|
|
131
132
|
headers=headers,
|
|
132
133
|
) as response:
|
|
133
134
|
response.raise_for_status()
|
|
134
|
-
response_data =
|
|
135
|
+
response_data = await self._read_json(response)
|
|
135
136
|
return self._process_response(response_data, base_path)
|
|
136
137
|
except aiohttp.ClientResponseError as e:
|
|
137
138
|
if e.status in HTTP_AUTH_STATUSES:
|
|
@@ -142,6 +143,33 @@ class BSBLANTransport:
|
|
|
142
143
|
msg = ErrorMsg.INVALID_RESPONSE.format(e)
|
|
143
144
|
raise BSBLANError(msg) from e
|
|
144
145
|
|
|
146
|
+
@staticmethod
|
|
147
|
+
async def _read_json(response: aiohttp.ClientResponse) -> dict[str, Any]:
|
|
148
|
+
"""Decode a BSB-LAN JSON response tolerant of non-UTF-8 encodings.
|
|
149
|
+
|
|
150
|
+
Some BSB-LAN firmwares serve custom parameter descriptions using
|
|
151
|
+
Latin-1 (ISO-8859-1) bytes (for example the ``§`` or ``°`` characters)
|
|
152
|
+
while declaring no charset. ``aiohttp`` assumes UTF-8 and raises
|
|
153
|
+
``UnicodeDecodeError``. Read the raw body and fall back to Latin-1,
|
|
154
|
+
which can decode any byte sequence, before parsing the JSON.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
response: The active aiohttp response to read.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
dict[str, Any]: The parsed JSON payload.
|
|
161
|
+
|
|
162
|
+
Raises:
|
|
163
|
+
ValueError: If the body is not valid JSON.
|
|
164
|
+
|
|
165
|
+
"""
|
|
166
|
+
raw = await response.read()
|
|
167
|
+
try:
|
|
168
|
+
text = raw.decode("utf-8")
|
|
169
|
+
except UnicodeDecodeError:
|
|
170
|
+
text = raw.decode("latin-1")
|
|
171
|
+
return cast("dict[str, Any]", json.loads(text))
|
|
172
|
+
|
|
145
173
|
def _process_response(
|
|
146
174
|
self, response_data: dict[str, Any], base_path: str
|
|
147
175
|
) -> dict[str, Any]:
|
|
@@ -71,13 +71,13 @@ async def test_value_error_path(monkeypatch: Any) -> None:
|
|
|
71
71
|
# Mock a successful response but with invalid JSON processing
|
|
72
72
|
mock_response = MagicMock()
|
|
73
73
|
mock_response.raise_for_status = MagicMock()
|
|
74
|
-
mock_response.
|
|
74
|
+
mock_response.read = AsyncMock(return_value=b"Invalid JSON")
|
|
75
75
|
mock_response.__aenter__ = AsyncMock(return_value=mock_response)
|
|
76
76
|
mock_response.__aexit__ = AsyncMock(return_value=None)
|
|
77
77
|
|
|
78
78
|
monkeypatch.setattr(session, "request", MagicMock(return_value=mock_response))
|
|
79
79
|
|
|
80
|
-
with pytest.raises(BSBLANError, match="Invalid
|
|
80
|
+
with pytest.raises(BSBLANError, match="Invalid response format"):
|
|
81
81
|
await bsblan._request()
|
|
82
82
|
|
|
83
83
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Tests for tolerant decoding of non-UTF-8 BSB-LAN responses."""
|
|
2
|
+
|
|
3
|
+
# file deepcode ignore W0212: this is a testfile
|
|
4
|
+
# pylint: disable=protected-access
|
|
5
|
+
|
|
6
|
+
import aiohttp
|
|
7
|
+
import pytest
|
|
8
|
+
from aresponses import ResponsesMockServer
|
|
9
|
+
|
|
10
|
+
from bsblan import BSBLAN
|
|
11
|
+
from bsblan.bsblan import BSBLANConfig
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.mark.asyncio
|
|
15
|
+
async def test_request_decodes_latin1_response(
|
|
16
|
+
aresponses: ResponsesMockServer,
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Latin-1 responses (e.g. custom descriptions with '§') are decoded."""
|
|
19
|
+
# "§" is byte 0xa7 in Latin-1 and is an invalid UTF-8 start byte.
|
|
20
|
+
payload = '{"700": {"name": "x", "desc": "Betrieb \u00a7", "value": "1"}}'
|
|
21
|
+
aresponses.add(
|
|
22
|
+
"example.com",
|
|
23
|
+
"/JQ",
|
|
24
|
+
"POST",
|
|
25
|
+
aresponses.Response(
|
|
26
|
+
status=200,
|
|
27
|
+
headers={"Content-Type": "application/json"},
|
|
28
|
+
body=payload.encode("latin-1"),
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
async with aiohttp.ClientSession() as session:
|
|
33
|
+
config = BSBLANConfig(host="example.com")
|
|
34
|
+
bsblan = BSBLAN(config, session=session)
|
|
35
|
+
response = await bsblan._request()
|
|
36
|
+
|
|
37
|
+
assert response["700"]["desc"] == "Betrieb \u00a7"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.mark.asyncio
|
|
41
|
+
async def test_request_decodes_utf8_response(
|
|
42
|
+
aresponses: ResponsesMockServer,
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Valid UTF-8 responses keep decoding correctly."""
|
|
45
|
+
payload = '{"700": {"name": "x", "desc": "Außentemperatur", "value": "1"}}'
|
|
46
|
+
aresponses.add(
|
|
47
|
+
"example.com",
|
|
48
|
+
"/JQ",
|
|
49
|
+
"POST",
|
|
50
|
+
aresponses.Response(
|
|
51
|
+
status=200,
|
|
52
|
+
headers={"Content-Type": "application/json"},
|
|
53
|
+
body=payload.encode("utf-8"),
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
async with aiohttp.ClientSession() as session:
|
|
58
|
+
config = BSBLANConfig(host="example.com")
|
|
59
|
+
bsblan = BSBLAN(config, session=session)
|
|
60
|
+
response = await bsblan._request()
|
|
61
|
+
|
|
62
|
+
assert response["700"]["desc"] == "Außentemperatur"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|