denonavr 0.11.6__py3-none-any.whl → 1.0.1__py3-none-any.whl
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.
- denonavr/__init__.py +1 -24
- denonavr/api.py +181 -94
- denonavr/audyssey.py +12 -7
- denonavr/const.py +168 -59
- denonavr/decorators.py +9 -76
- denonavr/denonavr.py +47 -187
- denonavr/foundation.py +126 -40
- denonavr/input.py +57 -9
- denonavr/soundmode.py +51 -36
- denonavr/tonecontrol.py +47 -12
- denonavr/volume.py +4 -2
- denonavr-1.0.1.dist-info/METADATA +158 -0
- denonavr-1.0.1.dist-info/RECORD +19 -0
- {denonavr-0.11.6.dist-info → denonavr-1.0.1.dist-info}/WHEEL +1 -1
- denonavr-0.11.6.dist-info/METADATA +0 -290
- denonavr-0.11.6.dist-info/RECORD +0 -19
- {denonavr-0.11.6.dist-info → denonavr-1.0.1.dist-info}/LICENSE +0 -0
- {denonavr-0.11.6.dist-info → denonavr-1.0.1.dist-info}/top_level.txt +0 -0
denonavr/const.py
CHANGED
|
@@ -43,6 +43,17 @@ ReceiverURLs = namedtuple(
|
|
|
43
43
|
"command_set_all_zone_stereo",
|
|
44
44
|
"command_pause",
|
|
45
45
|
"command_play",
|
|
46
|
+
"command_cusor_up",
|
|
47
|
+
"command_cusor_down",
|
|
48
|
+
"command_cusor_left",
|
|
49
|
+
"command_cusor_right",
|
|
50
|
+
"command_cusor_enter",
|
|
51
|
+
"command_back",
|
|
52
|
+
"command_info",
|
|
53
|
+
"command_options",
|
|
54
|
+
"command_setup_open",
|
|
55
|
+
"command_setup_close",
|
|
56
|
+
"command_setup_query",
|
|
46
57
|
],
|
|
47
58
|
)
|
|
48
59
|
TelnetCommands = namedtuple(
|
|
@@ -68,6 +79,17 @@ TelnetCommands = namedtuple(
|
|
|
68
79
|
"command_tonecontrol",
|
|
69
80
|
"command_bass",
|
|
70
81
|
"command_treble",
|
|
82
|
+
"command_cusor_up",
|
|
83
|
+
"command_cusor_down",
|
|
84
|
+
"command_cusor_left",
|
|
85
|
+
"command_cusor_right",
|
|
86
|
+
"command_cusor_enter",
|
|
87
|
+
"command_back",
|
|
88
|
+
"command_info",
|
|
89
|
+
"command_options",
|
|
90
|
+
"command_setup_open",
|
|
91
|
+
"command_setup_close",
|
|
92
|
+
"command_setup_query",
|
|
71
93
|
],
|
|
72
94
|
)
|
|
73
95
|
|
|
@@ -168,40 +190,40 @@ ALL_ZONE_STEREO = "ALL ZONE STEREO"
|
|
|
168
190
|
|
|
169
191
|
SOUND_MODE_MAPPING = {
|
|
170
192
|
"MUSIC": [
|
|
171
|
-
"
|
|
172
|
-
"
|
|
193
|
+
"DOLBY D +NEO:X M",
|
|
194
|
+
"DOLBY PL2 M",
|
|
195
|
+
"DOLBY PL2 MUSIC",
|
|
196
|
+
"DOLBY PL2 X MUSIC",
|
|
173
197
|
"DTS NEO:6 M",
|
|
198
|
+
"DTS NEO:6 MUSIC",
|
|
174
199
|
"DTS NEO:X M",
|
|
175
|
-
"DOLBY D +NEO:X M",
|
|
176
200
|
"DTS NEO:X MUSIC",
|
|
177
|
-
"
|
|
178
|
-
"DOLBY PL2 M",
|
|
201
|
+
"PLII MUSIC",
|
|
179
202
|
"PLIIX MUSIC",
|
|
180
|
-
"DOLBY PL2 X MUSIC",
|
|
181
203
|
],
|
|
182
204
|
"MOVIE": [
|
|
183
|
-
"PLII MOVIE",
|
|
184
|
-
"PLII CINEMA",
|
|
185
|
-
"DTS NEO:X CINEMA",
|
|
186
|
-
"DTS NEO:X C",
|
|
187
|
-
"DTS NEO:6 CINEMA",
|
|
188
|
-
"DTS NEO:6 C",
|
|
189
205
|
"DOLBY D +NEO:X C",
|
|
190
|
-
"PLIIX CINEMA",
|
|
191
|
-
"DOLBY PLII MOVIE",
|
|
192
|
-
"MULTI IN + VIRTUAL:X",
|
|
193
|
-
"DOLBY PL2 CINEMA",
|
|
194
206
|
"DOLBY PL2 C",
|
|
195
|
-
"DOLBY PL2
|
|
207
|
+
"DOLBY PL2 CINEMA",
|
|
196
208
|
"DOLBY PL2 MOVIE",
|
|
209
|
+
"DOLBY PL2 X MOVIE",
|
|
210
|
+
"DOLBY PLII MOVIE",
|
|
211
|
+
"DTS NEO:6 C",
|
|
212
|
+
"DTS NEO:6 CINEMA",
|
|
213
|
+
"DTS NEO:X C",
|
|
214
|
+
"DTS NEO:X CINEMA",
|
|
215
|
+
"MULTI IN + VIRTUAL:X",
|
|
216
|
+
"PLII CINEMA",
|
|
217
|
+
"PLII MOVIE",
|
|
218
|
+
"PLIIX CINEMA",
|
|
197
219
|
],
|
|
198
220
|
"GAME": [
|
|
199
|
-
"PLII GAME",
|
|
200
221
|
"DOLBY D +NEO:X G",
|
|
201
|
-
"DOLBY PL2 GAME",
|
|
202
222
|
"DOLBY PL2 G",
|
|
223
|
+
"DOLBY PL2 GAME",
|
|
203
224
|
"DOLBY PL2 X GAME",
|
|
204
225
|
"DOLBY PLII GAME",
|
|
226
|
+
"PLII GAME",
|
|
205
227
|
],
|
|
206
228
|
"AUTO": ["None"],
|
|
207
229
|
"STANDARD": ["None2"],
|
|
@@ -214,64 +236,74 @@ SOUND_MODE_MAPPING = {
|
|
|
214
236
|
"DIRECT": ["DIRECT"],
|
|
215
237
|
"PURE DIRECT": ["PURE_DIRECT", "PURE DIRECT"],
|
|
216
238
|
"DOLBY DIGITAL": [
|
|
217
|
-
"DOLBY DIGITAL",
|
|
218
|
-
"DOLBY D + DOLBY SURROUND",
|
|
219
|
-
"DOLBY D+DS",
|
|
220
|
-
"DOLBY D+ +DS",
|
|
221
|
-
"DOLBY DIGITAL +",
|
|
222
|
-
"STANDARD(DOLBY)",
|
|
223
|
-
"DOLBY SURROUND",
|
|
224
|
-
"DOLBY D + +DOLBY SURROUND",
|
|
225
|
-
"NEURAL",
|
|
226
|
-
"NEURAL:X",
|
|
227
|
-
"DOLBY HD",
|
|
228
|
-
"DOLBY HD + DOLBY SURROUND",
|
|
229
|
-
"MULTI IN + DSUR",
|
|
230
|
-
"MULTI IN + NEURAL:X",
|
|
231
|
-
"MULTI IN + DOLBY SURROUND",
|
|
232
|
-
"DOLBY D + NEURAL:X",
|
|
233
|
-
"DOLBY DIGITAL + NEURAL:X",
|
|
234
|
-
"DOLBY DIGITAL + + NEURAL:X",
|
|
235
239
|
"DOLBY ATMOS",
|
|
236
|
-
"DOLBY AUDIO -
|
|
237
|
-
"DOLBY
|
|
240
|
+
"DOLBY AUDIO - DD + DSUR",
|
|
241
|
+
"DOLBY AUDIO - DD + NEURAL:X",
|
|
242
|
+
"DOLBY AUDIO - DD+ + DSUR",
|
|
243
|
+
"DOLBY AUDIO - DD+ + NEURAL:X",
|
|
238
244
|
"DOLBY AUDIO - DOLBY DIGITAL PLUS",
|
|
239
|
-
"DOLBY AUDIO -
|
|
245
|
+
"DOLBY AUDIO - DOLBY DIGITAL",
|
|
246
|
+
"DOLBY AUDIO - DOLBY SURROUND",
|
|
240
247
|
"DOLBY AUDIO - DOLBY TRUEHD",
|
|
248
|
+
"DOLBY AUDIO - TRUEHD + DSUR",
|
|
241
249
|
"DOLBY AUDIO - TRUEHD + NEURAL:X",
|
|
242
|
-
"DOLBY AUDIO
|
|
243
|
-
"DOLBY AUDIO - DD + DSUR",
|
|
244
|
-
"DOLBY AUDIO - DD+ + NEURAL:X",
|
|
245
|
-
"DOLBY AUDIO - DD+ + DSUR",
|
|
250
|
+
"DOLBY AUDIO-DD",
|
|
246
251
|
"DOLBY AUDIO-DD+ +DSUR",
|
|
247
|
-
"DOLBY AUDIO
|
|
248
|
-
"DOLBY AUDIO-
|
|
252
|
+
"DOLBY AUDIO-DD+ +NEURAL:X",
|
|
253
|
+
"DOLBY AUDIO-DD+",
|
|
249
254
|
"DOLBY AUDIO-DD+DSUR",
|
|
255
|
+
"DOLBY AUDIO-DSUR",
|
|
256
|
+
"DOLBY AUDIO-TRUEHD",
|
|
257
|
+
"DOLBY AUDIO-TRUEHD+DSUR",
|
|
258
|
+
"DOLBY AUDIO-TRUEHD+NEURAL:X",
|
|
259
|
+
"DOLBY D + +DOLBY SURROUND",
|
|
260
|
+
"DOLBY D + DOLBY SURROUND",
|
|
261
|
+
"DOLBY D + NEURAL:X",
|
|
262
|
+
"DOLBY D+ +DS",
|
|
263
|
+
"DOLBY D+",
|
|
264
|
+
"DOLBY D+DS",
|
|
265
|
+
"DOLBY DIGITAL + + NEURAL:X",
|
|
266
|
+
"DOLBY DIGITAL + NEURAL:X",
|
|
267
|
+
"DOLBY DIGITAL +",
|
|
268
|
+
"DOLBY DIGITAL",
|
|
269
|
+
"DOLBY HD + DOLBY SURROUND",
|
|
270
|
+
"DOLBY HD",
|
|
250
271
|
"DOLBY PRO LOGIC",
|
|
272
|
+
"DOLBY SURROUND",
|
|
273
|
+
"DOLBY TRUEHD",
|
|
274
|
+
"MULTI IN + DOLBY SURROUND",
|
|
275
|
+
"MULTI IN + DSUR",
|
|
276
|
+
"MULTI IN + NEURAL:X",
|
|
277
|
+
"NEURAL",
|
|
278
|
+
"STANDARD(DOLBY)",
|
|
251
279
|
],
|
|
252
280
|
"DTS SURROUND": [
|
|
253
|
-
"DTS SURROUND",
|
|
254
|
-
"DTS NEURAL:X",
|
|
255
|
-
"STANDARD(DTS)",
|
|
281
|
+
"DTS + DOLBY SURROUND",
|
|
256
282
|
"DTS + NEURAL:X",
|
|
257
|
-
"MULTI CH IN",
|
|
258
|
-
"DTS-HD MSTR",
|
|
259
|
-
"DTS VIRTUAL:X",
|
|
260
|
-
"DTS-HD + NEURAL:X",
|
|
261
|
-
"DTS-HD",
|
|
262
283
|
"DTS + VIRTUAL:X",
|
|
263
|
-
"DTS
|
|
284
|
+
"DTS NEURAL:X",
|
|
285
|
+
"DTS SURROUND",
|
|
286
|
+
"DTS VIRTUAL:X",
|
|
264
287
|
"DTS-HD + DOLBY SURROUND",
|
|
265
288
|
"DTS-HD + DSUR",
|
|
289
|
+
"DTS-HD + NEURAL:X",
|
|
290
|
+
"DTS-HD MSTR",
|
|
291
|
+
"DTS-HD",
|
|
266
292
|
"DTS:X MSTR",
|
|
293
|
+
"DTS:X",
|
|
294
|
+
"M CH IN+DSUR",
|
|
295
|
+
"MULTI CH IN",
|
|
296
|
+
"NEURAL:X",
|
|
297
|
+
"STANDARD(DTS)",
|
|
298
|
+
"VIRTUAL:X",
|
|
267
299
|
],
|
|
268
|
-
"AURO3D": ["AURO-3D"],
|
|
269
|
-
"AURO2DSURR": ["AURO-2D SURROUND"],
|
|
300
|
+
"AURO3D": ["AURO-3D", "AURO3D"],
|
|
301
|
+
"AURO2DSURR": ["AURO-2D SURROUND", "AURO2DSURR"],
|
|
270
302
|
"MCH STEREO": [
|
|
271
|
-
"MULTI CH STEREO",
|
|
272
|
-
"MULTI_CH_STEREO",
|
|
273
303
|
"MCH STEREO",
|
|
274
304
|
"MULTI CH IN 7.1",
|
|
305
|
+
"MULTI CH STEREO",
|
|
306
|
+
"MULTI_CH_STEREO",
|
|
275
307
|
],
|
|
276
308
|
"STEREO": ["STEREO"],
|
|
277
309
|
ALL_ZONE_STEREO: ["ALL ZONE STEREO"],
|
|
@@ -327,6 +359,17 @@ COMMAND_MUTE_ON_URL = "/goform/formiPhoneAppMute.xml?1+MuteOn"
|
|
|
327
359
|
COMMAND_MUTE_OFF_URL = "/goform/formiPhoneAppMute.xml?1+MuteOff"
|
|
328
360
|
COMMAND_SEL_SM_URL = "/goform/formiPhoneAppDirect.xml?MS"
|
|
329
361
|
COMMAND_SET_ZST_URL = "/goform/formiPhoneAppDirect.xml?MN"
|
|
362
|
+
COMMAND_CURSOR_UP = "/goform/formiPhoneAppDirect.xml?MNCUP"
|
|
363
|
+
COMMAND_CURSOR_DOWN = "/goform/formiPhoneAppDirect.xml?MNCDN"
|
|
364
|
+
COMMAND_CURSOR_LEFT = "/goform/formiPhoneAppDirect.xml?MNCLT"
|
|
365
|
+
COMMAND_CURSOR_RIGHT = "/goform/formiPhoneAppDirect.xml?MNCRT"
|
|
366
|
+
COMMAND_CURSOR_ENTER = "/goform/formiPhoneAppDirect.xml?MNENT"
|
|
367
|
+
COMMAND_BACK = "/goform/formiPhoneAppDirect.xml?MNRTN"
|
|
368
|
+
COMMAND_INFO = "/goform/formiPhoneAppDirect.xml?MNINF"
|
|
369
|
+
COMMAND_OPTIONS = "/goform/formiPhoneAppDirect.xml?MNOPT"
|
|
370
|
+
COMMAND_SETUP_OPEN = "/goform/formiPhoneAppDirect.xml?MNMEN%20ON"
|
|
371
|
+
COMMAND_SETUP_CLOSE = "/goform/formiPhoneAppDirect.xml?MNMEN%20OFF"
|
|
372
|
+
COMMAND_SETUP_QUERY = "/goform/formiPhoneAppDirect.xml?MNMEN?"
|
|
330
373
|
|
|
331
374
|
# Zone 2 URLs
|
|
332
375
|
STATUS_Z2_URL = "/goform/formZone2_Zone2XmlStatus.xml"
|
|
@@ -375,6 +418,17 @@ DENONAVR_URLS = ReceiverURLs(
|
|
|
375
418
|
command_set_all_zone_stereo=COMMAND_SET_ZST_URL,
|
|
376
419
|
command_pause=COMMAND_PAUSE,
|
|
377
420
|
command_play=COMMAND_PLAY,
|
|
421
|
+
command_cusor_up=COMMAND_CURSOR_UP,
|
|
422
|
+
command_cusor_down=COMMAND_CURSOR_DOWN,
|
|
423
|
+
command_cusor_left=COMMAND_CURSOR_LEFT,
|
|
424
|
+
command_cusor_right=COMMAND_CURSOR_RIGHT,
|
|
425
|
+
command_cusor_enter=COMMAND_CURSOR_ENTER,
|
|
426
|
+
command_back=COMMAND_BACK,
|
|
427
|
+
command_info=COMMAND_INFO,
|
|
428
|
+
command_options=COMMAND_OPTIONS,
|
|
429
|
+
command_setup_open=COMMAND_SETUP_OPEN,
|
|
430
|
+
command_setup_close=COMMAND_SETUP_CLOSE,
|
|
431
|
+
command_setup_query=COMMAND_SETUP_QUERY,
|
|
378
432
|
)
|
|
379
433
|
|
|
380
434
|
ZONE2_URLS = ReceiverURLs(
|
|
@@ -400,6 +454,17 @@ ZONE2_URLS = ReceiverURLs(
|
|
|
400
454
|
command_set_all_zone_stereo=COMMAND_SET_ZST_URL,
|
|
401
455
|
command_pause=COMMAND_PAUSE,
|
|
402
456
|
command_play=COMMAND_PLAY,
|
|
457
|
+
command_cusor_up=COMMAND_CURSOR_UP,
|
|
458
|
+
command_cusor_down=COMMAND_CURSOR_DOWN,
|
|
459
|
+
command_cusor_left=COMMAND_CURSOR_LEFT,
|
|
460
|
+
command_cusor_right=COMMAND_CURSOR_RIGHT,
|
|
461
|
+
command_cusor_enter=COMMAND_CURSOR_ENTER,
|
|
462
|
+
command_back=COMMAND_BACK,
|
|
463
|
+
command_info=COMMAND_INFO,
|
|
464
|
+
command_options=COMMAND_OPTIONS,
|
|
465
|
+
command_setup_open=COMMAND_SETUP_OPEN,
|
|
466
|
+
command_setup_close=COMMAND_SETUP_CLOSE,
|
|
467
|
+
command_setup_query=COMMAND_SETUP_QUERY,
|
|
403
468
|
)
|
|
404
469
|
|
|
405
470
|
ZONE3_URLS = ReceiverURLs(
|
|
@@ -425,6 +490,17 @@ ZONE3_URLS = ReceiverURLs(
|
|
|
425
490
|
command_set_all_zone_stereo=COMMAND_SET_ZST_URL,
|
|
426
491
|
command_pause=COMMAND_PAUSE,
|
|
427
492
|
command_play=COMMAND_PLAY,
|
|
493
|
+
command_cusor_up=COMMAND_CURSOR_UP,
|
|
494
|
+
command_cusor_down=COMMAND_CURSOR_DOWN,
|
|
495
|
+
command_cusor_left=COMMAND_CURSOR_LEFT,
|
|
496
|
+
command_cusor_right=COMMAND_CURSOR_RIGHT,
|
|
497
|
+
command_cusor_enter=COMMAND_CURSOR_ENTER,
|
|
498
|
+
command_back=COMMAND_BACK,
|
|
499
|
+
command_info=COMMAND_INFO,
|
|
500
|
+
command_options=COMMAND_OPTIONS,
|
|
501
|
+
command_setup_open=COMMAND_SETUP_OPEN,
|
|
502
|
+
command_setup_close=COMMAND_SETUP_CLOSE,
|
|
503
|
+
command_setup_query=COMMAND_SETUP_QUERY,
|
|
428
504
|
)
|
|
429
505
|
|
|
430
506
|
# Telnet Events
|
|
@@ -503,6 +579,17 @@ DENONAVR_TELNET_COMMANDS = TelnetCommands(
|
|
|
503
579
|
command_tonecontrol="PSTONE CTRL ",
|
|
504
580
|
command_bass="PSBAS ",
|
|
505
581
|
command_treble="PSTRE ",
|
|
582
|
+
command_cusor_up="MNCUP",
|
|
583
|
+
command_cusor_down="MNCDN",
|
|
584
|
+
command_cusor_left="MNCLT",
|
|
585
|
+
command_cusor_right="MNCRT",
|
|
586
|
+
command_cusor_enter="MNENT",
|
|
587
|
+
command_back="MNRTN",
|
|
588
|
+
command_info="MNINF",
|
|
589
|
+
command_options="MNOPT",
|
|
590
|
+
command_setup_open="MNMEN ON",
|
|
591
|
+
command_setup_close="MNMEN OFF",
|
|
592
|
+
command_setup_query="MNMEN?",
|
|
506
593
|
)
|
|
507
594
|
|
|
508
595
|
ZONE2_TELNET_COMMANDS = TelnetCommands(
|
|
@@ -526,6 +613,17 @@ ZONE2_TELNET_COMMANDS = TelnetCommands(
|
|
|
526
613
|
command_tonecontrol="PSTONE CTRL ",
|
|
527
614
|
command_bass="PSBAS ",
|
|
528
615
|
command_treble="PSTRE ",
|
|
616
|
+
command_cusor_up="MNCUP",
|
|
617
|
+
command_cusor_down="MNCDN",
|
|
618
|
+
command_cusor_left="MNCLT",
|
|
619
|
+
command_cusor_right="MNCRT",
|
|
620
|
+
command_cusor_enter="MNENT",
|
|
621
|
+
command_back="MNRTN",
|
|
622
|
+
command_info="MNINF",
|
|
623
|
+
command_options="MNOPT",
|
|
624
|
+
command_setup_open="MNMEN ON",
|
|
625
|
+
command_setup_close="MNMEN OFF",
|
|
626
|
+
command_setup_query="MNMEN?",
|
|
529
627
|
)
|
|
530
628
|
|
|
531
629
|
ZONE3_TELNET_COMMANDS = TelnetCommands(
|
|
@@ -549,6 +647,17 @@ ZONE3_TELNET_COMMANDS = TelnetCommands(
|
|
|
549
647
|
command_tonecontrol="PSTONE CTRL ",
|
|
550
648
|
command_bass="PSBAS ",
|
|
551
649
|
command_treble="PSTRE ",
|
|
650
|
+
command_cusor_up="MNCUP",
|
|
651
|
+
command_cusor_down="MNCDN",
|
|
652
|
+
command_cusor_left="MNCLT",
|
|
653
|
+
command_cusor_right="MNCRT",
|
|
654
|
+
command_cusor_enter="MNENT",
|
|
655
|
+
command_back="MNRTN",
|
|
656
|
+
command_info="MNINF",
|
|
657
|
+
command_options="MNOPT",
|
|
658
|
+
command_setup_open="MNMEN ON",
|
|
659
|
+
command_setup_close="MNMEN OFF",
|
|
660
|
+
command_setup_query="MNMEN?",
|
|
552
661
|
)
|
|
553
662
|
|
|
554
663
|
# States
|
denonavr/decorators.py
CHANGED
|
@@ -7,18 +7,14 @@ This module implements the REST API to Denon AVR receivers.
|
|
|
7
7
|
:license: MIT, see LICENSE for more details.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
import asyncio
|
|
11
10
|
import inspect
|
|
12
11
|
import logging
|
|
13
12
|
import time
|
|
14
|
-
import xml.etree.ElementTree as ET
|
|
15
13
|
from functools import wraps
|
|
16
|
-
from typing import Callable,
|
|
14
|
+
from typing import Callable, TypeVar
|
|
17
15
|
|
|
18
16
|
import httpx
|
|
19
17
|
from asyncstdlib import lru_cache
|
|
20
|
-
from defusedxml import DefusedXmlException
|
|
21
|
-
from defusedxml.ElementTree import ParseError
|
|
22
18
|
|
|
23
19
|
from .exceptions import (
|
|
24
20
|
AvrForbiddenError,
|
|
@@ -34,118 +30,55 @@ AnyT = TypeVar("AnyT")
|
|
|
34
30
|
|
|
35
31
|
|
|
36
32
|
def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
|
|
37
|
-
"""
|
|
38
|
-
Handle exceptions raised when calling a Denon AVR endpoint asynchronously.
|
|
39
|
-
|
|
40
|
-
The decorated function must either have a string variable as second
|
|
41
|
-
argument or as "request" keyword argument.
|
|
42
|
-
"""
|
|
33
|
+
"""Handle exceptions raised when calling a Denon AVR endpoint asynchronously."""
|
|
43
34
|
|
|
44
35
|
@wraps(func)
|
|
45
36
|
async def wrapper(*args, **kwargs):
|
|
46
37
|
try:
|
|
47
38
|
return await func(*args, **kwargs)
|
|
48
39
|
except httpx.HTTPStatusError as err:
|
|
49
|
-
_LOGGER.debug("HTTP status error on request %s", err.request,
|
|
40
|
+
_LOGGER.debug("HTTP status error on request %s: %s", err.request, err)
|
|
50
41
|
# Separate handling of 403 errors
|
|
51
42
|
if err.response.status_code == 403:
|
|
52
43
|
raise AvrForbiddenError(f"HTTPStatusError: {err}", err.request) from err
|
|
53
44
|
raise AvrRequestError(f"HTTPStatusError: {err}", err.request) from err
|
|
54
45
|
except httpx.TimeoutException as err:
|
|
55
|
-
_LOGGER.debug(
|
|
56
|
-
"HTTP timeout exception on request %s", err.request, exc_info=True
|
|
57
|
-
)
|
|
46
|
+
_LOGGER.debug("HTTP timeout exception on request %s: %s", err.request, err)
|
|
58
47
|
raise AvrTimoutError(f"TimeoutException: {err}", err.request) from err
|
|
59
48
|
except httpx.NetworkError as err:
|
|
60
|
-
_LOGGER.debug(
|
|
61
|
-
"Network error exception on request %s", err.request, exc_info=True
|
|
62
|
-
)
|
|
49
|
+
_LOGGER.debug("Network error exception on request %s: %s", err.request, err)
|
|
63
50
|
raise AvrNetworkError(f"NetworkError: {err}", err.request) from err
|
|
64
51
|
except httpx.RemoteProtocolError as err:
|
|
65
52
|
_LOGGER.debug(
|
|
66
53
|
"Remote protocol error exception on request %s",
|
|
67
54
|
err.request,
|
|
68
|
-
exc_info=True,
|
|
69
55
|
)
|
|
70
56
|
raise AvrInvalidResponseError(
|
|
71
57
|
f"RemoteProtocolError: {err}", err.request
|
|
72
58
|
) from err
|
|
73
|
-
except (
|
|
74
|
-
ET.ParseError,
|
|
75
|
-
DefusedXmlException,
|
|
76
|
-
ParseError,
|
|
77
|
-
UnicodeDecodeError,
|
|
78
|
-
) as err:
|
|
79
|
-
_LOGGER.debug(
|
|
80
|
-
"Defusedxml parse error on request %s", (args, kwargs), exc_info=True
|
|
81
|
-
)
|
|
82
|
-
raise AvrInvalidResponseError(
|
|
83
|
-
f"XMLParseError: {err}", (args, kwargs)
|
|
84
|
-
) from err
|
|
85
59
|
|
|
86
60
|
return wrapper
|
|
87
61
|
|
|
88
62
|
|
|
89
63
|
def cache_result(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
|
|
90
64
|
"""
|
|
91
|
-
Decorate a function to cache its results with an lru_cache of maxsize
|
|
65
|
+
Decorate a function to cache its results with an lru_cache of maxsize 32.
|
|
92
66
|
|
|
93
67
|
This decorator also sets an "cache_id" keyword argument if it is not set yet.
|
|
94
|
-
When an exception occurs it clears lru_cache to prevent memory leaks in
|
|
95
|
-
home-assistant when receiver instances are created and deleted right
|
|
96
|
-
away in case the device is offline on setup.
|
|
97
68
|
"""
|
|
98
69
|
if inspect.signature(func).parameters.get("cache_id") is None:
|
|
99
70
|
raise AttributeError(
|
|
100
71
|
f"Function {func} does not have a 'cache_id' keyword parameter"
|
|
101
72
|
)
|
|
102
73
|
|
|
103
|
-
lru_decorator = lru_cache(maxsize=
|
|
74
|
+
lru_decorator = lru_cache(maxsize=32)
|
|
104
75
|
cached_func = lru_decorator(func)
|
|
105
76
|
|
|
106
77
|
@wraps(func)
|
|
107
78
|
async def wrapper(*args, **kwargs):
|
|
108
79
|
if kwargs.get("cache_id") is None:
|
|
109
80
|
kwargs["cache_id"] = time.time()
|
|
110
|
-
try:
|
|
111
|
-
return await cached_func(*args, **kwargs)
|
|
112
|
-
except Exception as err:
|
|
113
|
-
_LOGGER.debug("Exception %s raised, clearing cache", err)
|
|
114
|
-
cached_func.cache_clear()
|
|
115
|
-
raise
|
|
116
81
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def run_async_synchronously(async_func: Coroutine) -> Callable:
|
|
121
|
-
"""
|
|
122
|
-
Decorate to run the configured asynchronous function synchronously instead.
|
|
123
|
-
|
|
124
|
-
If available the corresponding function with async_ prefix is called in an
|
|
125
|
-
own event loop. This is not efficient but it ensures backwards
|
|
126
|
-
compatibility of this library.
|
|
127
|
-
"""
|
|
82
|
+
return await cached_func(*args, **kwargs)
|
|
128
83
|
|
|
129
|
-
|
|
130
|
-
# Check if function is a coroutine
|
|
131
|
-
if not inspect.iscoroutinefunction(async_func):
|
|
132
|
-
raise AttributeError(f"Function {async_func} is not a coroutine function")
|
|
133
|
-
# Check if the signature of both functions is equal
|
|
134
|
-
if inspect.signature(func) != inspect.signature(async_func):
|
|
135
|
-
raise AttributeError(
|
|
136
|
-
f"Functions {func} and {async_func} have different signatures"
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
@wraps(func)
|
|
140
|
-
def wrapper(*args, **kwargs):
|
|
141
|
-
# Run async function in own event loop
|
|
142
|
-
loop = asyncio.new_event_loop()
|
|
143
|
-
|
|
144
|
-
try:
|
|
145
|
-
return loop.run_until_complete(async_func(*args, **kwargs))
|
|
146
|
-
finally:
|
|
147
|
-
loop.close()
|
|
148
|
-
|
|
149
|
-
return wrapper
|
|
150
|
-
|
|
151
|
-
return decorator
|
|
84
|
+
return wrapper
|