parsek-cdp 0.1.0__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.
- parsek_cdp/__init__.py +55 -0
- parsek_cdp/_logging.py +49 -0
- parsek_cdp/cdp/__init__.py +247 -0
- parsek_cdp/cdp/accessibility/__init__.py +15 -0
- parsek_cdp/cdp/accessibility/events.py +35 -0
- parsek_cdp/cdp/accessibility/functions.py +202 -0
- parsek_cdp/cdp/accessibility/types.py +235 -0
- parsek_cdp/cdp/animation/__init__.py +15 -0
- parsek_cdp/cdp/animation/events.py +52 -0
- parsek_cdp/cdp/animation/functions.py +140 -0
- parsek_cdp/cdp/animation/types.py +113 -0
- parsek_cdp/cdp/audits/__init__.py +15 -0
- parsek_cdp/cdp/audits/events.py +21 -0
- parsek_cdp/cdp/audits/functions.py +95 -0
- parsek_cdp/cdp/audits/types.py +1051 -0
- parsek_cdp/cdp/autofill/__init__.py +15 -0
- parsek_cdp/cdp/autofill/events.py +27 -0
- parsek_cdp/cdp/autofill/functions.py +64 -0
- parsek_cdp/cdp/autofill/types.py +108 -0
- parsek_cdp/cdp/backgroundservice/__init__.py +15 -0
- parsek_cdp/cdp/backgroundservice/events.py +40 -0
- parsek_cdp/cdp/backgroundservice/functions.py +59 -0
- parsek_cdp/cdp/backgroundservice/types.py +63 -0
- parsek_cdp/cdp/bluetoothemulation/__init__.py +15 -0
- parsek_cdp/cdp/bluetoothemulation/events.py +70 -0
- parsek_cdp/cdp/bluetoothemulation/functions.py +247 -0
- parsek_cdp/cdp/bluetoothemulation/types.py +120 -0
- parsek_cdp/cdp/browser/__init__.py +15 -0
- parsek_cdp/cdp/browser/events.py +46 -0
- parsek_cdp/cdp/browser/functions.py +350 -0
- parsek_cdp/cdp/browser/types.py +158 -0
- parsek_cdp/cdp/cachestorage/__init__.py +15 -0
- parsek_cdp/cdp/cachestorage/events.py +13 -0
- parsek_cdp/cdp/cachestorage/functions.py +126 -0
- parsek_cdp/cdp/cachestorage/types.py +89 -0
- parsek_cdp/cdp/cast/__init__.py +15 -0
- parsek_cdp/cdp/cast/events.py +38 -0
- parsek_cdp/cdp/cast/functions.py +77 -0
- parsek_cdp/cdp/cast/types.py +23 -0
- parsek_cdp/cdp/console/__init__.py +15 -0
- parsek_cdp/cdp/console/events.py +22 -0
- parsek_cdp/cdp/console/functions.py +36 -0
- parsek_cdp/cdp/console/types.py +30 -0
- parsek_cdp/cdp/css/__init__.py +15 -0
- parsek_cdp/cdp/css/events.py +79 -0
- parsek_cdp/cdp/css/functions.py +788 -0
- parsek_cdp/cdp/css/types.py +742 -0
- parsek_cdp/cdp/debugger/__init__.py +15 -0
- parsek_cdp/cdp/debugger/events.py +164 -0
- parsek_cdp/cdp/debugger/functions.py +663 -0
- parsek_cdp/cdp/debugger/types.py +171 -0
- parsek_cdp/cdp/deviceaccess/__init__.py +15 -0
- parsek_cdp/cdp/deviceaccess/events.py +30 -0
- parsek_cdp/cdp/deviceaccess/functions.py +54 -0
- parsek_cdp/cdp/deviceaccess/types.py +28 -0
- parsek_cdp/cdp/deviceorientation/__init__.py +15 -0
- parsek_cdp/cdp/deviceorientation/events.py +13 -0
- parsek_cdp/cdp/deviceorientation/functions.py +35 -0
- parsek_cdp/cdp/deviceorientation/types.py +10 -0
- parsek_cdp/cdp/dom/__init__.py +15 -0
- parsek_cdp/cdp/dom/events.py +228 -0
- parsek_cdp/cdp/dom/functions.py +1033 -0
- parsek_cdp/cdp/dom/types.py +293 -0
- parsek_cdp/cdp/domdebugger/__init__.py +15 -0
- parsek_cdp/cdp/domdebugger/events.py +13 -0
- parsek_cdp/cdp/domdebugger/functions.py +155 -0
- parsek_cdp/cdp/domdebugger/types.py +57 -0
- parsek_cdp/cdp/domsnapshot/__init__.py +15 -0
- parsek_cdp/cdp/domsnapshot/events.py +13 -0
- parsek_cdp/cdp/domsnapshot/functions.py +111 -0
- parsek_cdp/cdp/domsnapshot/types.py +312 -0
- parsek_cdp/cdp/domstorage/__init__.py +15 -0
- parsek_cdp/cdp/domstorage/events.py +60 -0
- parsek_cdp/cdp/domstorage/functions.py +79 -0
- parsek_cdp/cdp/domstorage/types.py +30 -0
- parsek_cdp/cdp/emulation/__init__.py +15 -0
- parsek_cdp/cdp/emulation/events.py +17 -0
- parsek_cdp/cdp/emulation/functions.py +688 -0
- parsek_cdp/cdp/emulation/types.py +305 -0
- parsek_cdp/cdp/eventbreakpoints/__init__.py +15 -0
- parsek_cdp/cdp/eventbreakpoints/events.py +13 -0
- parsek_cdp/cdp/eventbreakpoints/functions.py +41 -0
- parsek_cdp/cdp/eventbreakpoints/types.py +10 -0
- parsek_cdp/cdp/extensions/__init__.py +15 -0
- parsek_cdp/cdp/extensions/events.py +13 -0
- parsek_cdp/cdp/extensions/functions.py +118 -0
- parsek_cdp/cdp/extensions/types.py +19 -0
- parsek_cdp/cdp/fedcm/__init__.py +15 -0
- parsek_cdp/cdp/fedcm/events.py +45 -0
- parsek_cdp/cdp/fedcm/functions.py +93 -0
- parsek_cdp/cdp/fedcm/types.py +72 -0
- parsek_cdp/cdp/fetch/__init__.py +15 -0
- parsek_cdp/cdp/fetch/events.py +82 -0
- parsek_cdp/cdp/fetch/functions.py +215 -0
- parsek_cdp/cdp/fetch/types.py +81 -0
- parsek_cdp/cdp/filesystem/__init__.py +15 -0
- parsek_cdp/cdp/filesystem/events.py +13 -0
- parsek_cdp/cdp/filesystem/functions.py +36 -0
- parsek_cdp/cdp/filesystem/types.py +54 -0
- parsek_cdp/cdp/headlessexperimental/__init__.py +15 -0
- parsek_cdp/cdp/headlessexperimental/events.py +13 -0
- parsek_cdp/cdp/headlessexperimental/functions.py +77 -0
- parsek_cdp/cdp/headlessexperimental/types.py +24 -0
- parsek_cdp/cdp/heapprofiler/__init__.py +15 -0
- parsek_cdp/cdp/heapprofiler/events.py +65 -0
- parsek_cdp/cdp/heapprofiler/functions.py +193 -0
- parsek_cdp/cdp/heapprofiler/types.py +57 -0
- parsek_cdp/cdp/indexeddb/__init__.py +15 -0
- parsek_cdp/cdp/indexeddb/events.py +13 -0
- parsek_cdp/cdp/indexeddb/functions.py +232 -0
- parsek_cdp/cdp/indexeddb/types.py +120 -0
- parsek_cdp/cdp/input/__init__.py +15 -0
- parsek_cdp/cdp/input/events.py +25 -0
- parsek_cdp/cdp/input/functions.py +361 -0
- parsek_cdp/cdp/input/types.py +87 -0
- parsek_cdp/cdp/inspector/__init__.py +15 -0
- parsek_cdp/cdp/inspector/events.py +41 -0
- parsek_cdp/cdp/inspector/functions.py +27 -0
- parsek_cdp/cdp/inspector/types.py +10 -0
- parsek_cdp/cdp/io/__init__.py +15 -0
- parsek_cdp/cdp/io/events.py +13 -0
- parsek_cdp/cdp/io/functions.py +77 -0
- parsek_cdp/cdp/io/types.py +13 -0
- parsek_cdp/cdp/layertree/__init__.py +15 -0
- parsek_cdp/cdp/layertree/events.py +36 -0
- parsek_cdp/cdp/layertree/functions.py +178 -0
- parsek_cdp/cdp/layertree/types.py +104 -0
- parsek_cdp/cdp/log/__init__.py +15 -0
- parsek_cdp/cdp/log/events.py +22 -0
- parsek_cdp/cdp/log/functions.py +54 -0
- parsek_cdp/cdp/log/types.py +57 -0
- parsek_cdp/cdp/media/__init__.py +15 -0
- parsek_cdp/cdp/media/events.py +87 -0
- parsek_cdp/cdp/media/functions.py +27 -0
- parsek_cdp/cdp/media/types.py +101 -0
- parsek_cdp/cdp/memory/__init__.py +15 -0
- parsek_cdp/cdp/memory/events.py +13 -0
- parsek_cdp/cdp/memory/functions.py +164 -0
- parsek_cdp/cdp/memory/types.py +71 -0
- parsek_cdp/cdp/mixins/__init__.py +21 -0
- parsek_cdp/cdp/mixins/datatype.py +123 -0
- parsek_cdp/cdp/mixins/event.py +78 -0
- parsek_cdp/cdp/mixins/namespace.py +31 -0
- parsek_cdp/cdp/network/__init__.py +15 -0
- parsek_cdp/cdp/network/events.py +726 -0
- parsek_cdp/cdp/network/functions.py +734 -0
- parsek_cdp/cdp/network/types.py +1247 -0
- parsek_cdp/cdp/overlay/__init__.py +15 -0
- parsek_cdp/cdp/overlay/events.py +54 -0
- parsek_cdp/cdp/overlay/functions.py +407 -0
- parsek_cdp/cdp/overlay/types.py +328 -0
- parsek_cdp/cdp/page/__init__.py +15 -0
- parsek_cdp/cdp/page/events.py +416 -0
- parsek_cdp/cdp/page/functions.py +1081 -0
- parsek_cdp/cdp/page/types.py +1088 -0
- parsek_cdp/cdp/performance/__init__.py +15 -0
- parsek_cdp/cdp/performance/events.py +24 -0
- parsek_cdp/cdp/performance/functions.py +63 -0
- parsek_cdp/cdp/performance/types.py +22 -0
- parsek_cdp/cdp/performancetimeline/__init__.py +15 -0
- parsek_cdp/cdp/performancetimeline/events.py +22 -0
- parsek_cdp/cdp/performancetimeline/functions.py +30 -0
- parsek_cdp/cdp/performancetimeline/types.py +85 -0
- parsek_cdp/cdp/preload/__init__.py +15 -0
- parsek_cdp/cdp/preload/events.py +116 -0
- parsek_cdp/cdp/preload/functions.py +25 -0
- parsek_cdp/cdp/preload/types.py +267 -0
- parsek_cdp/cdp/profiler/__init__.py +15 -0
- parsek_cdp/cdp/profiler/events.py +64 -0
- parsek_cdp/cdp/profiler/functions.py +134 -0
- parsek_cdp/cdp/profiler/types.py +105 -0
- parsek_cdp/cdp/pwa/__init__.py +15 -0
- parsek_cdp/cdp/pwa/events.py +13 -0
- parsek_cdp/cdp/pwa/functions.py +196 -0
- parsek_cdp/cdp/pwa/types.py +45 -0
- parsek_cdp/cdp/runtime/__init__.py +15 -0
- parsek_cdp/cdp/runtime/events.py +123 -0
- parsek_cdp/cdp/runtime/functions.py +552 -0
- parsek_cdp/cdp/runtime/types.py +319 -0
- parsek_cdp/cdp/schema/__init__.py +15 -0
- parsek_cdp/cdp/schema/events.py +13 -0
- parsek_cdp/cdp/schema/functions.py +32 -0
- parsek_cdp/cdp/schema/types.py +22 -0
- parsek_cdp/cdp/security/__init__.py +15 -0
- parsek_cdp/cdp/security/events.py +64 -0
- parsek_cdp/cdp/security/functions.py +66 -0
- parsek_cdp/cdp/security/types.py +168 -0
- parsek_cdp/cdp/serviceworker/__init__.py +15 -0
- parsek_cdp/cdp/serviceworker/events.py +43 -0
- parsek_cdp/cdp/serviceworker/functions.py +115 -0
- parsek_cdp/cdp/serviceworker/types.py +95 -0
- parsek_cdp/cdp/storage/__init__.py +15 -0
- parsek_cdp/cdp/storage/events.py +288 -0
- parsek_cdp/cdp/storage/functions.py +571 -0
- parsek_cdp/cdp/storage/types.py +656 -0
- parsek_cdp/cdp/systeminfo/__init__.py +15 -0
- parsek_cdp/cdp/systeminfo/events.py +13 -0
- parsek_cdp/cdp/systeminfo/functions.py +75 -0
- parsek_cdp/cdp/systeminfo/types.py +132 -0
- parsek_cdp/cdp/target/__init__.py +15 -0
- parsek_cdp/cdp/target/events.py +109 -0
- parsek_cdp/cdp/target/functions.py +424 -0
- parsek_cdp/cdp/target/types.py +83 -0
- parsek_cdp/cdp/tethering/__init__.py +15 -0
- parsek_cdp/cdp/tethering/events.py +22 -0
- parsek_cdp/cdp/tethering/functions.py +35 -0
- parsek_cdp/cdp/tethering/types.py +10 -0
- parsek_cdp/cdp/tracing/__init__.py +15 -0
- parsek_cdp/cdp/tracing/events.py +61 -0
- parsek_cdp/cdp/tracing/functions.py +119 -0
- parsek_cdp/cdp/tracing/types.py +81 -0
- parsek_cdp/cdp/webaudio/__init__.py +15 -0
- parsek_cdp/cdp/webaudio/events.py +184 -0
- parsek_cdp/cdp/webaudio/functions.py +51 -0
- parsek_cdp/cdp/webaudio/types.py +155 -0
- parsek_cdp/cdp/webauthn/__init__.py +15 -0
- parsek_cdp/cdp/webauthn/events.py +69 -0
- parsek_cdp/cdp/webauthn/functions.py +214 -0
- parsek_cdp/cdp/webauthn/types.py +96 -0
- parsek_cdp/core/__init__.py +18 -0
- parsek_cdp/core/browser.py +240 -0
- parsek_cdp/core/browser_context.py +58 -0
- parsek_cdp/core/element.py +405 -0
- parsek_cdp/core/feature.py +376 -0
- parsek_cdp/core/frame.py +351 -0
- parsek_cdp/core/pagable.py +175 -0
- parsek_cdp/core/page.py +163 -0
- parsek_cdp/core/target.py +490 -0
- parsek_cdp/features/__init__.py +14 -0
- parsek_cdp/features/request_listener/__init__.py +256 -0
- parsek_cdp/features/request_listener/events.py +48 -0
- parsek_cdp/features/request_listener/types.py +235 -0
- parsek_cdp/generate.py +642 -0
- parsek_cdp/parsek/__init__.py +18 -0
- parsek_cdp/parsek/events.py +38 -0
- parsek_cdp/parsek/types.py +36 -0
- parsek_cdp/py.typed +0 -0
- parsek_cdp-0.1.0.dist-info/METADATA +277 -0
- parsek_cdp-0.1.0.dist-info/RECORD +242 -0
- parsek_cdp-0.1.0.dist-info/WHEEL +5 -0
- parsek_cdp-0.1.0.dist-info/licenses/LICENSE +201 -0
- parsek_cdp-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Events for the Media domain (generated)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Literal, Optional
|
|
6
|
+
|
|
7
|
+
from ..mixins.datatype import FieldMeta
|
|
8
|
+
from ..mixins.event import Event, register_event
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from .types import (
|
|
12
|
+
Player,
|
|
13
|
+
PlayerError,
|
|
14
|
+
PlayerEvent,
|
|
15
|
+
PlayerId,
|
|
16
|
+
PlayerMessage,
|
|
17
|
+
PlayerProperty,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
@register_event("Media.playerPropertiesChanged")
|
|
21
|
+
@dataclass
|
|
22
|
+
class PlayerPropertiesChanged(Event):
|
|
23
|
+
"""
|
|
24
|
+
This can be called multiple times, and can be used to set / override /
|
|
25
|
+
remove player properties. A null propValue indicates removal.
|
|
26
|
+
"""
|
|
27
|
+
player_id: PlayerId
|
|
28
|
+
properties: List[PlayerProperty]
|
|
29
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
30
|
+
FieldMeta('player_id', 'playerId', False, 'primitive'),
|
|
31
|
+
FieldMeta('properties', 'properties', False, 'array', inner=FieldMeta('', '', False, 'object', ref='Media.PlayerProperty')),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@register_event("Media.playerEventsAdded")
|
|
36
|
+
@dataclass
|
|
37
|
+
class PlayerEventsAdded(Event):
|
|
38
|
+
"""
|
|
39
|
+
Send events as a list, allowing them to be batched on the browser for less
|
|
40
|
+
congestion. If batched, events must ALWAYS be in chronological order.
|
|
41
|
+
"""
|
|
42
|
+
player_id: PlayerId
|
|
43
|
+
events: List[PlayerEvent]
|
|
44
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
45
|
+
FieldMeta('player_id', 'playerId', False, 'primitive'),
|
|
46
|
+
FieldMeta('events', 'events', False, 'array', inner=FieldMeta('', '', False, 'object', ref='Media.PlayerEvent')),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@register_event("Media.playerMessagesLogged")
|
|
51
|
+
@dataclass
|
|
52
|
+
class PlayerMessagesLogged(Event):
|
|
53
|
+
"""Send a list of any messages that need to be delivered."""
|
|
54
|
+
player_id: PlayerId
|
|
55
|
+
messages: List[PlayerMessage]
|
|
56
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
57
|
+
FieldMeta('player_id', 'playerId', False, 'primitive'),
|
|
58
|
+
FieldMeta('messages', 'messages', False, 'array', inner=FieldMeta('', '', False, 'object', ref='Media.PlayerMessage')),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@register_event("Media.playerErrorsRaised")
|
|
63
|
+
@dataclass
|
|
64
|
+
class PlayerErrorsRaised(Event):
|
|
65
|
+
"""Send a list of any errors that need to be delivered."""
|
|
66
|
+
player_id: PlayerId
|
|
67
|
+
errors: List[PlayerError]
|
|
68
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
69
|
+
FieldMeta('player_id', 'playerId', False, 'primitive'),
|
|
70
|
+
FieldMeta('errors', 'errors', False, 'array', inner=FieldMeta('', '', False, 'object', ref='Media.PlayerError')),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@register_event("Media.playerCreated")
|
|
75
|
+
@dataclass
|
|
76
|
+
class PlayerCreated(Event):
|
|
77
|
+
"""
|
|
78
|
+
Called whenever a player is created, or when a new agent joins and receives
|
|
79
|
+
a list of active players. If an agent is restored, it will receive one
|
|
80
|
+
event for each active player.
|
|
81
|
+
"""
|
|
82
|
+
player: Player
|
|
83
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
84
|
+
FieldMeta('player', 'player', False, 'object', ref='Media.Player'),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
__all__ = ["PlayerCreated", "PlayerErrorsRaised", "PlayerEventsAdded", "PlayerMessagesLogged", "PlayerPropertiesChanged"]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Commands for the Media domain (generated)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, ClassVar, Dict, List, Literal, Optional
|
|
6
|
+
|
|
7
|
+
from ..mixins.datatype import DataType, FieldMeta, encode
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Media:
|
|
11
|
+
"""Commands of the Media domain, bound to a target."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, target: Any) -> None:
|
|
14
|
+
self._target = target
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def enable(self) -> None:
|
|
18
|
+
"""Enables the Media domain"""
|
|
19
|
+
_params: Dict[str, Any] = {}
|
|
20
|
+
_result = await self._target.send('Media.enable', _params)
|
|
21
|
+
return None
|
|
22
|
+
|
|
23
|
+
async def disable(self) -> None:
|
|
24
|
+
"""Disables the Media domain."""
|
|
25
|
+
_params: Dict[str, Any] = {}
|
|
26
|
+
_result = await self._target.send('Media.disable', _params)
|
|
27
|
+
return None
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Custom types and enums for the Media domain (generated)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Literal, Optional
|
|
7
|
+
|
|
8
|
+
from ..mixins.datatype import DataType, FieldMeta, register
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..dom.types import BackendNodeId as DOM_BackendNodeId
|
|
12
|
+
|
|
13
|
+
type PlayerId = str # Players will get an ID that is unique within the agent context.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
type Timestamp = float
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@register("Media.PlayerMessage")
|
|
20
|
+
@dataclass
|
|
21
|
+
class PlayerMessage(DataType):
|
|
22
|
+
"""
|
|
23
|
+
Have one type per entry in MediaLogRecord::Type
|
|
24
|
+
Corresponds to kMessage
|
|
25
|
+
"""
|
|
26
|
+
level: Literal['error', 'warning', 'info', 'debug']
|
|
27
|
+
message: str
|
|
28
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
29
|
+
FieldMeta('level', 'level', False, 'primitive'),
|
|
30
|
+
FieldMeta('message', 'message', False, 'primitive'),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@register("Media.PlayerProperty")
|
|
35
|
+
@dataclass
|
|
36
|
+
class PlayerProperty(DataType):
|
|
37
|
+
"""Corresponds to kMediaPropertyChange"""
|
|
38
|
+
name: str
|
|
39
|
+
value: str
|
|
40
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
41
|
+
FieldMeta('name', 'name', False, 'primitive'),
|
|
42
|
+
FieldMeta('value', 'value', False, 'primitive'),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@register("Media.PlayerEvent")
|
|
47
|
+
@dataclass
|
|
48
|
+
class PlayerEvent(DataType):
|
|
49
|
+
"""Corresponds to kMediaEventTriggered"""
|
|
50
|
+
timestamp: Timestamp
|
|
51
|
+
value: str
|
|
52
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
53
|
+
FieldMeta('timestamp', 'timestamp', False, 'primitive'),
|
|
54
|
+
FieldMeta('value', 'value', False, 'primitive'),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@register("Media.PlayerErrorSourceLocation")
|
|
59
|
+
@dataclass
|
|
60
|
+
class PlayerErrorSourceLocation(DataType):
|
|
61
|
+
"""
|
|
62
|
+
Represents logged source line numbers reported in an error.
|
|
63
|
+
NOTE: file and line are from chromium c++ implementation code, not js.
|
|
64
|
+
"""
|
|
65
|
+
file: str
|
|
66
|
+
line: int
|
|
67
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
68
|
+
FieldMeta('file', 'file', False, 'primitive'),
|
|
69
|
+
FieldMeta('line', 'line', False, 'primitive'),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@register("Media.PlayerError")
|
|
74
|
+
@dataclass
|
|
75
|
+
class PlayerError(DataType):
|
|
76
|
+
"""Corresponds to kMediaError"""
|
|
77
|
+
error_type: str
|
|
78
|
+
code: int
|
|
79
|
+
stack: List[PlayerErrorSourceLocation]
|
|
80
|
+
cause: List[PlayerError]
|
|
81
|
+
data: Dict[str, Any]
|
|
82
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
83
|
+
FieldMeta('error_type', 'errorType', False, 'primitive'),
|
|
84
|
+
FieldMeta('code', 'code', False, 'primitive'),
|
|
85
|
+
FieldMeta('stack', 'stack', False, 'array', inner=FieldMeta('', '', False, 'object', ref='Media.PlayerErrorSourceLocation')),
|
|
86
|
+
FieldMeta('cause', 'cause', False, 'array', inner=FieldMeta('', '', False, 'object', ref='Media.PlayerError')),
|
|
87
|
+
FieldMeta('data', 'data', False, 'primitive'),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@register("Media.Player")
|
|
92
|
+
@dataclass
|
|
93
|
+
class Player(DataType):
|
|
94
|
+
player_id: PlayerId
|
|
95
|
+
dom_node_id: Optional[DOM_BackendNodeId] = None
|
|
96
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
97
|
+
FieldMeta('player_id', 'playerId', False, 'primitive'),
|
|
98
|
+
FieldMeta('dom_node_id', 'domNodeId', True, 'primitive'),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
__all__ = ["Player", "PlayerError", "PlayerErrorSourceLocation", "PlayerEvent", "PlayerId", "PlayerMessage", "PlayerProperty", "Timestamp"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""The Memory CDP domain (generated).
|
|
2
|
+
|
|
3
|
+
Importing ``Memory`` from ``parsek_cdp.cdp`` gives a namespace with this
|
|
4
|
+
domain's events and types as attributes (``Memory.SomeEvent`` /
|
|
5
|
+
``Memory.SomeType``); commands run on a target via ``page.cdp.Memory``.
|
|
6
|
+
"""
|
|
7
|
+
from . import events, functions, types
|
|
8
|
+
from .functions import Memory
|
|
9
|
+
from .events import * # noqa: F401,F403 -- expose events on the namespace
|
|
10
|
+
from .types import * # noqa: F401,F403 -- expose types on the namespace
|
|
11
|
+
|
|
12
|
+
#: Protocol domain name (used by features that declare ``domains=(Memory,)``).
|
|
13
|
+
DOMAIN = "Memory"
|
|
14
|
+
|
|
15
|
+
__all__ = ["events", "functions", "types", "Memory", "DOMAIN"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Events for the Memory domain (generated)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, ClassVar, Dict, List, Literal, Optional
|
|
6
|
+
|
|
7
|
+
from ..mixins.datatype import FieldMeta
|
|
8
|
+
from ..mixins.event import Event, register_event
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# This domain defines no events.
|
|
12
|
+
|
|
13
|
+
__all__ = []
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Commands for the Memory domain (generated)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Literal, Optional
|
|
6
|
+
|
|
7
|
+
from ..mixins.datatype import DataType, FieldMeta, encode
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from .types import (
|
|
11
|
+
DOMCounter,
|
|
12
|
+
PressureLevel,
|
|
13
|
+
SamplingProfile,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class GetDOMCountersReturn(DataType):
|
|
18
|
+
"""Return value of :meth:`Memory.get_dom_counters`."""
|
|
19
|
+
documents: int
|
|
20
|
+
nodes: int
|
|
21
|
+
js_event_listeners: int
|
|
22
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
23
|
+
FieldMeta('documents', 'documents', False, 'primitive'),
|
|
24
|
+
FieldMeta('nodes', 'nodes', False, 'primitive'),
|
|
25
|
+
FieldMeta('js_event_listeners', 'jsEventListeners', False, 'primitive'),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class GetDOMCountersForLeakDetectionReturn(DataType):
|
|
31
|
+
"""Return value of :meth:`Memory.get_dom_counters_for_leak_detection`."""
|
|
32
|
+
counters: List[DOMCounter]
|
|
33
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
34
|
+
FieldMeta('counters', 'counters', False, 'array', inner=FieldMeta('', '', False, 'object', ref='Memory.DOMCounter')),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class GetAllTimeSamplingProfileReturn(DataType):
|
|
40
|
+
"""Return value of :meth:`Memory.get_all_time_sampling_profile`."""
|
|
41
|
+
profile: SamplingProfile
|
|
42
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
43
|
+
FieldMeta('profile', 'profile', False, 'object', ref='Memory.SamplingProfile'),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class GetBrowserSamplingProfileReturn(DataType):
|
|
49
|
+
"""Return value of :meth:`Memory.get_browser_sampling_profile`."""
|
|
50
|
+
profile: SamplingProfile
|
|
51
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
52
|
+
FieldMeta('profile', 'profile', False, 'object', ref='Memory.SamplingProfile'),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class GetSamplingProfileReturn(DataType):
|
|
58
|
+
"""Return value of :meth:`Memory.get_sampling_profile`."""
|
|
59
|
+
profile: SamplingProfile
|
|
60
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
61
|
+
FieldMeta('profile', 'profile', False, 'object', ref='Memory.SamplingProfile'),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class Memory:
|
|
66
|
+
"""Commands of the Memory domain, bound to a target."""
|
|
67
|
+
|
|
68
|
+
def __init__(self, target: Any) -> None:
|
|
69
|
+
self._target = target
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def get_dom_counters(self) -> GetDOMCountersReturn:
|
|
73
|
+
"""Retruns current DOM object counters."""
|
|
74
|
+
_params: Dict[str, Any] = {}
|
|
75
|
+
_result = await self._target.send('Memory.getDOMCounters', _params)
|
|
76
|
+
return GetDOMCountersReturn.from_json(_result)
|
|
77
|
+
|
|
78
|
+
async def get_dom_counters_for_leak_detection(self) -> GetDOMCountersForLeakDetectionReturn:
|
|
79
|
+
"""Retruns DOM object counters after preparing renderer for leak detection."""
|
|
80
|
+
_params: Dict[str, Any] = {}
|
|
81
|
+
_result = await self._target.send('Memory.getDOMCountersForLeakDetection', _params)
|
|
82
|
+
return GetDOMCountersForLeakDetectionReturn.from_json(_result)
|
|
83
|
+
|
|
84
|
+
async def prepare_for_leak_detection(self) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Prepares for leak detection by terminating workers, stopping spellcheckers,
|
|
87
|
+
dropping non-essential internal caches, running garbage collections, etc.
|
|
88
|
+
"""
|
|
89
|
+
_params: Dict[str, Any] = {}
|
|
90
|
+
_result = await self._target.send('Memory.prepareForLeakDetection', _params)
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
async def forcibly_purge_java_script_memory(self) -> None:
|
|
94
|
+
"""Simulate OomIntervention by purging V8 memory."""
|
|
95
|
+
_params: Dict[str, Any] = {}
|
|
96
|
+
_result = await self._target.send('Memory.forciblyPurgeJavaScriptMemory', _params)
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
async def set_pressure_notifications_suppressed(self, *, suppressed: bool) -> None:
|
|
100
|
+
"""
|
|
101
|
+
Enable/disable suppressing memory pressure notifications in all processes.
|
|
102
|
+
:param suppressed: If true, memory pressure notifications will be suppressed.
|
|
103
|
+
"""
|
|
104
|
+
_params: Dict[str, Any] = {}
|
|
105
|
+
_params['suppressed'] = encode(FieldMeta('', '', False, 'primitive'), suppressed)
|
|
106
|
+
_result = await self._target.send('Memory.setPressureNotificationsSuppressed', _params)
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
async def simulate_pressure_notification(self, *, level: PressureLevel) -> None:
|
|
110
|
+
"""
|
|
111
|
+
Simulate a memory pressure notification in all processes.
|
|
112
|
+
:param level: Memory pressure level of the notification.
|
|
113
|
+
"""
|
|
114
|
+
_params: Dict[str, Any] = {}
|
|
115
|
+
_params['level'] = encode(FieldMeta('', '', False, 'enum', ref='Memory.PressureLevel'), level)
|
|
116
|
+
_result = await self._target.send('Memory.simulatePressureNotification', _params)
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
async def start_sampling(self, *, sampling_interval: Optional[int] = None, suppress_randomness: Optional[bool] = None) -> None:
|
|
120
|
+
"""
|
|
121
|
+
Start collecting native memory profile.
|
|
122
|
+
:param sampling_interval: Average number of bytes between samples.
|
|
123
|
+
:param suppress_randomness: Do not randomize intervals between samples.
|
|
124
|
+
"""
|
|
125
|
+
_params: Dict[str, Any] = {}
|
|
126
|
+
if sampling_interval is not None:
|
|
127
|
+
_params['samplingInterval'] = encode(FieldMeta('', '', False, 'primitive'), sampling_interval)
|
|
128
|
+
if suppress_randomness is not None:
|
|
129
|
+
_params['suppressRandomness'] = encode(FieldMeta('', '', False, 'primitive'), suppress_randomness)
|
|
130
|
+
_result = await self._target.send('Memory.startSampling', _params)
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
async def stop_sampling(self) -> None:
|
|
134
|
+
"""Stop collecting native memory profile."""
|
|
135
|
+
_params: Dict[str, Any] = {}
|
|
136
|
+
_result = await self._target.send('Memory.stopSampling', _params)
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
async def get_all_time_sampling_profile(self) -> GetAllTimeSamplingProfileReturn:
|
|
140
|
+
"""
|
|
141
|
+
Retrieve native memory allocations profile
|
|
142
|
+
collected since renderer process startup.
|
|
143
|
+
"""
|
|
144
|
+
_params: Dict[str, Any] = {}
|
|
145
|
+
_result = await self._target.send('Memory.getAllTimeSamplingProfile', _params)
|
|
146
|
+
return GetAllTimeSamplingProfileReturn.from_json(_result)
|
|
147
|
+
|
|
148
|
+
async def get_browser_sampling_profile(self) -> GetBrowserSamplingProfileReturn:
|
|
149
|
+
"""
|
|
150
|
+
Retrieve native memory allocations profile
|
|
151
|
+
collected since browser process startup.
|
|
152
|
+
"""
|
|
153
|
+
_params: Dict[str, Any] = {}
|
|
154
|
+
_result = await self._target.send('Memory.getBrowserSamplingProfile', _params)
|
|
155
|
+
return GetBrowserSamplingProfileReturn.from_json(_result)
|
|
156
|
+
|
|
157
|
+
async def get_sampling_profile(self) -> GetSamplingProfileReturn:
|
|
158
|
+
"""
|
|
159
|
+
Retrieve native memory allocations profile collected since last
|
|
160
|
+
`startSampling` call.
|
|
161
|
+
"""
|
|
162
|
+
_params: Dict[str, Any] = {}
|
|
163
|
+
_result = await self._target.send('Memory.getSamplingProfile', _params)
|
|
164
|
+
return GetSamplingProfileReturn.from_json(_result)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Custom types and enums for the Memory domain (generated)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Any, ClassVar, Dict, List, Literal, Optional
|
|
7
|
+
|
|
8
|
+
from ..mixins.datatype import DataType, FieldMeta, register
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@register("Memory.PressureLevel")
|
|
12
|
+
class PressureLevel(str, Enum):
|
|
13
|
+
"""Memory pressure level."""
|
|
14
|
+
MODERATE = 'moderate'
|
|
15
|
+
CRITICAL = 'critical'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@register("Memory.SamplingProfileNode")
|
|
19
|
+
@dataclass
|
|
20
|
+
class SamplingProfileNode(DataType):
|
|
21
|
+
"""Heap profile sample."""
|
|
22
|
+
size: float
|
|
23
|
+
total: float
|
|
24
|
+
stack: List[str]
|
|
25
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
26
|
+
FieldMeta('size', 'size', False, 'primitive'),
|
|
27
|
+
FieldMeta('total', 'total', False, 'primitive'),
|
|
28
|
+
FieldMeta('stack', 'stack', False, 'array', inner=FieldMeta('', '', False, 'primitive')),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@register("Memory.SamplingProfile")
|
|
33
|
+
@dataclass
|
|
34
|
+
class SamplingProfile(DataType):
|
|
35
|
+
"""Array of heap profile samples."""
|
|
36
|
+
samples: List[SamplingProfileNode]
|
|
37
|
+
modules: List[Module]
|
|
38
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
39
|
+
FieldMeta('samples', 'samples', False, 'array', inner=FieldMeta('', '', False, 'object', ref='Memory.SamplingProfileNode')),
|
|
40
|
+
FieldMeta('modules', 'modules', False, 'array', inner=FieldMeta('', '', False, 'object', ref='Memory.Module')),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@register("Memory.Module")
|
|
45
|
+
@dataclass
|
|
46
|
+
class Module(DataType):
|
|
47
|
+
"""Executable module information"""
|
|
48
|
+
name: str
|
|
49
|
+
uuid: str
|
|
50
|
+
base_address: str
|
|
51
|
+
size: float
|
|
52
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
53
|
+
FieldMeta('name', 'name', False, 'primitive'),
|
|
54
|
+
FieldMeta('uuid', 'uuid', False, 'primitive'),
|
|
55
|
+
FieldMeta('base_address', 'baseAddress', False, 'primitive'),
|
|
56
|
+
FieldMeta('size', 'size', False, 'primitive'),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@register("Memory.DOMCounter")
|
|
61
|
+
@dataclass
|
|
62
|
+
class DOMCounter(DataType):
|
|
63
|
+
"""DOM object counter data."""
|
|
64
|
+
name: str
|
|
65
|
+
count: int
|
|
66
|
+
__FIELDS__: ClassVar[tuple] = (
|
|
67
|
+
FieldMeta('name', 'name', False, 'primitive'),
|
|
68
|
+
FieldMeta('count', 'count', False, 'primitive'),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
__all__ = ["DOMCounter", "Module", "PressureLevel", "SamplingProfile", "SamplingProfileNode"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .datatype import (
|
|
2
|
+
TYPE_REGISTRY,
|
|
3
|
+
DataType,
|
|
4
|
+
FieldMeta,
|
|
5
|
+
decode,
|
|
6
|
+
encode,
|
|
7
|
+
register,
|
|
8
|
+
)
|
|
9
|
+
from .event import EVENT_REGISTRY, Event, register_event
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"TYPE_REGISTRY",
|
|
13
|
+
"DataType",
|
|
14
|
+
"FieldMeta",
|
|
15
|
+
"decode",
|
|
16
|
+
"encode",
|
|
17
|
+
"register",
|
|
18
|
+
"EVENT_REGISTRY",
|
|
19
|
+
"Event",
|
|
20
|
+
"register_event",
|
|
21
|
+
]
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Base machinery for CDP data types.
|
|
2
|
+
|
|
3
|
+
A ``DataType`` behaves like a :func:`dataclasses.dataclass` but additionally
|
|
4
|
+
knows how to serialize/deserialize itself to/from the JSON shapes used on the
|
|
5
|
+
wire by the Chrome DevTools Protocol.
|
|
6
|
+
|
|
7
|
+
Python uses ``snake_case`` identifiers while the protocol uses ``camelCase``
|
|
8
|
+
keys, so a plain ``dataclasses.asdict`` is not enough -- every field carries a
|
|
9
|
+
:class:`FieldMeta` describing both names plus how nested values are encoded.
|
|
10
|
+
|
|
11
|
+
To avoid import cycles between domains (CDP has many cross-domain references,
|
|
12
|
+
some of them circular) nested enum / object types are resolved lazily at
|
|
13
|
+
runtime through :data:`TYPE_REGISTRY` keyed by the fully-qualified protocol
|
|
14
|
+
name (``"Domain.TypeName"``).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from enum import Enum
|
|
21
|
+
from typing import Any, Callable, ClassVar, Optional, TypeVar
|
|
22
|
+
|
|
23
|
+
# Fully-qualified protocol name ("Domain.TypeName") -> python class.
|
|
24
|
+
# Only enums and object data types are registered; aliases to primitives or
|
|
25
|
+
# arrays are resolved at generation time and never need a runtime lookup.
|
|
26
|
+
TYPE_REGISTRY: dict[str, type] = {}
|
|
27
|
+
|
|
28
|
+
T = TypeVar("T")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def register(qualified_name: str) -> Callable[[type[T]], type[T]]:
|
|
32
|
+
"""Class decorator registering ``cls`` under its protocol name.
|
|
33
|
+
|
|
34
|
+
The class's concrete type is preserved so type checkers still see its
|
|
35
|
+
fields after decoration.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def deco(cls: type[T]) -> type[T]:
|
|
39
|
+
TYPE_REGISTRY[qualified_name] = cls
|
|
40
|
+
return cls
|
|
41
|
+
|
|
42
|
+
return deco
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class FieldMeta:
|
|
47
|
+
"""Describes how a single field maps between python and the wire format.
|
|
48
|
+
|
|
49
|
+
``kind`` is one of ``"primitive"``, ``"enum"``, ``"object"`` or
|
|
50
|
+
``"array"``. ``ref`` holds the fully-qualified protocol name for
|
|
51
|
+
``enum``/``object`` kinds. ``inner`` holds the element metadata for
|
|
52
|
+
``array`` kinds.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
py_name: str
|
|
56
|
+
json_name: str
|
|
57
|
+
optional: bool
|
|
58
|
+
kind: str
|
|
59
|
+
ref: Optional[str] = None
|
|
60
|
+
inner: Optional["FieldMeta"] = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def decode(meta: FieldMeta, value: Any) -> Any:
|
|
64
|
+
"""Convert a raw JSON ``value`` into its python representation."""
|
|
65
|
+
if value is None:
|
|
66
|
+
return None
|
|
67
|
+
if meta.kind == "primitive":
|
|
68
|
+
return value
|
|
69
|
+
if meta.kind == "enum":
|
|
70
|
+
return TYPE_REGISTRY[meta.ref](value) # type: ignore[index]
|
|
71
|
+
if meta.kind == "object":
|
|
72
|
+
return TYPE_REGISTRY[meta.ref].from_json(value) # type: ignore[union-attr]
|
|
73
|
+
if meta.kind == "array":
|
|
74
|
+
assert meta.inner is not None
|
|
75
|
+
return [decode(meta.inner, v) for v in value]
|
|
76
|
+
return value
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def encode(meta: FieldMeta, value: Any) -> Any:
|
|
80
|
+
"""Convert a python ``value`` into its raw JSON representation."""
|
|
81
|
+
if value is None:
|
|
82
|
+
return None
|
|
83
|
+
if meta.kind == "primitive":
|
|
84
|
+
return value
|
|
85
|
+
if meta.kind == "enum":
|
|
86
|
+
return value.value if isinstance(value, Enum) else value
|
|
87
|
+
if meta.kind == "object":
|
|
88
|
+
return value.to_json() if isinstance(value, DataType) else value
|
|
89
|
+
if meta.kind == "array":
|
|
90
|
+
assert meta.inner is not None
|
|
91
|
+
return [encode(meta.inner, v) for v in value]
|
|
92
|
+
return value
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class DataType:
|
|
96
|
+
"""Mixin providing JSON (de)serialization driven by :data:`__FIELDS__`."""
|
|
97
|
+
|
|
98
|
+
__FIELDS__: ClassVar[tuple[FieldMeta, ...]] = ()
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def from_json(cls, data: dict[str, Any]):
|
|
102
|
+
"""Build an instance from a raw protocol object.
|
|
103
|
+
|
|
104
|
+
Tolerant of protocol drift: a field the running browser omits (e.g. a
|
|
105
|
+
"required" field renamed in a newer Chrome than the bundled schema) is
|
|
106
|
+
set to ``None`` instead of raising, and unknown extra keys in ``data``
|
|
107
|
+
are ignored since only declared :data:`__FIELDS__` are read.
|
|
108
|
+
"""
|
|
109
|
+
kwargs: dict[str, Any] = {}
|
|
110
|
+
for fm in cls.__FIELDS__:
|
|
111
|
+
raw = data.get(fm.json_name)
|
|
112
|
+
kwargs[fm.py_name] = decode(fm, raw) if raw is not None else None
|
|
113
|
+
return cls(**kwargs)
|
|
114
|
+
|
|
115
|
+
def to_json(self) -> dict[str, Any]:
|
|
116
|
+
"""Serialize to a raw protocol object, dropping unset optionals."""
|
|
117
|
+
out: dict[str, Any] = {}
|
|
118
|
+
for fm in self.__FIELDS__:
|
|
119
|
+
value = getattr(self, fm.py_name)
|
|
120
|
+
if value is None and fm.optional:
|
|
121
|
+
continue
|
|
122
|
+
out[fm.json_name] = encode(fm, value)
|
|
123
|
+
return out
|