maqet 0.0.1.3__py3-none-any.whl → 0.0.5__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.
Files changed (83) hide show
  1. maqet/__init__.py +50 -6
  2. maqet/__main__.py +96 -0
  3. maqet/__version__.py +3 -0
  4. maqet/api/__init__.py +35 -0
  5. maqet/api/decorators.py +184 -0
  6. maqet/api/metadata.py +147 -0
  7. maqet/api/registry.py +182 -0
  8. maqet/cli.py +71 -0
  9. maqet/config/__init__.py +26 -0
  10. maqet/config/merger.py +237 -0
  11. maqet/config/parser.py +198 -0
  12. maqet/config/validators.py +519 -0
  13. maqet/config_handlers.py +684 -0
  14. maqet/constants.py +200 -0
  15. maqet/exceptions.py +226 -0
  16. maqet/formatters.py +294 -0
  17. maqet/generators/__init__.py +12 -0
  18. maqet/generators/base_generator.py +101 -0
  19. maqet/generators/cli_generator.py +635 -0
  20. maqet/generators/python_generator.py +247 -0
  21. maqet/generators/rest_generator.py +58 -0
  22. maqet/handlers/__init__.py +12 -0
  23. maqet/handlers/base.py +108 -0
  24. maqet/handlers/init.py +147 -0
  25. maqet/handlers/stage.py +196 -0
  26. maqet/ipc/__init__.py +29 -0
  27. maqet/ipc/retry.py +265 -0
  28. maqet/ipc/runner_client.py +285 -0
  29. maqet/ipc/unix_socket_server.py +239 -0
  30. maqet/logger.py +160 -55
  31. maqet/machine.py +884 -0
  32. maqet/managers/__init__.py +7 -0
  33. maqet/managers/qmp_manager.py +333 -0
  34. maqet/managers/snapshot_coordinator.py +327 -0
  35. maqet/managers/vm_manager.py +683 -0
  36. maqet/maqet.py +1120 -0
  37. maqet/os_interactions.py +46 -0
  38. maqet/process_spawner.py +395 -0
  39. maqet/qemu_args.py +76 -0
  40. maqet/qmp/__init__.py +10 -0
  41. maqet/qmp/commands.py +92 -0
  42. maqet/qmp/keyboard.py +311 -0
  43. maqet/qmp/qmp.py +17 -0
  44. maqet/snapshot.py +473 -0
  45. maqet/state.py +958 -0
  46. maqet/storage.py +702 -162
  47. maqet/validation/__init__.py +9 -0
  48. maqet/validation/config_validator.py +170 -0
  49. maqet/vm_runner.py +523 -0
  50. maqet-0.0.5.dist-info/METADATA +237 -0
  51. maqet-0.0.5.dist-info/RECORD +55 -0
  52. {maqet-0.0.1.3.dist-info → maqet-0.0.5.dist-info}/WHEEL +1 -1
  53. maqet-0.0.5.dist-info/entry_points.txt +2 -0
  54. maqet-0.0.5.dist-info/licenses/LICENSE +21 -0
  55. {maqet-0.0.1.3.dist-info → maqet-0.0.5.dist-info}/top_level.txt +0 -1
  56. maqet/core.py +0 -395
  57. maqet/functions.py +0 -104
  58. maqet-0.0.1.3.dist-info/METADATA +0 -104
  59. maqet-0.0.1.3.dist-info/RECORD +0 -33
  60. qemu/machine/__init__.py +0 -36
  61. qemu/machine/console_socket.py +0 -142
  62. qemu/machine/machine.py +0 -954
  63. qemu/machine/py.typed +0 -0
  64. qemu/machine/qtest.py +0 -191
  65. qemu/qmp/__init__.py +0 -59
  66. qemu/qmp/error.py +0 -50
  67. qemu/qmp/events.py +0 -717
  68. qemu/qmp/legacy.py +0 -319
  69. qemu/qmp/message.py +0 -209
  70. qemu/qmp/models.py +0 -146
  71. qemu/qmp/protocol.py +0 -1057
  72. qemu/qmp/py.typed +0 -0
  73. qemu/qmp/qmp_client.py +0 -655
  74. qemu/qmp/qmp_shell.py +0 -618
  75. qemu/qmp/qmp_tui.py +0 -655
  76. qemu/qmp/util.py +0 -219
  77. qemu/utils/__init__.py +0 -162
  78. qemu/utils/accel.py +0 -84
  79. qemu/utils/py.typed +0 -0
  80. qemu/utils/qemu_ga_client.py +0 -323
  81. qemu/utils/qom.py +0 -273
  82. qemu/utils/qom_common.py +0 -175
  83. qemu/utils/qom_fuse.py +0 -207
qemu/qmp/legacy.py DELETED
@@ -1,319 +0,0 @@
1
- """
2
- (Legacy) Sync QMP Wrapper
3
-
4
- This module provides the `QEMUMonitorProtocol` class, which is a
5
- synchronous wrapper around `QMPClient`.
6
-
7
- Its design closely resembles that of the original QEMUMonitorProtocol
8
- class, originally written by Luiz Capitulino. It is provided here for
9
- compatibility with scripts inside the QEMU source tree that expect the
10
- old interface.
11
- """
12
-
13
- #
14
- # Copyright (C) 2009-2022 Red Hat Inc.
15
- #
16
- # Authors:
17
- # Luiz Capitulino <lcapitulino@redhat.com>
18
- # John Snow <jsnow@redhat.com>
19
- #
20
- # This work is licensed under the terms of the GNU GPL, version 2. See
21
- # the COPYING file in the top-level directory.
22
- #
23
-
24
- import asyncio
25
- import socket
26
- from types import TracebackType
27
- from typing import (
28
- Any,
29
- Awaitable,
30
- Dict,
31
- List,
32
- Optional,
33
- Type,
34
- TypeVar,
35
- Union,
36
- )
37
-
38
- from .error import QMPError
39
- from .protocol import Runstate, SocketAddrT
40
- from .qmp_client import QMPClient
41
-
42
-
43
- #: QMPMessage is an entire QMP message of any kind.
44
- QMPMessage = Dict[str, Any]
45
-
46
- #: QMPReturnValue is the 'return' value of a command.
47
- QMPReturnValue = object
48
-
49
- #: QMPObject is any object in a QMP message.
50
- QMPObject = Dict[str, object]
51
-
52
- # QMPMessage can be outgoing commands or incoming events/returns.
53
- # QMPReturnValue is usually a dict/json object, but due to QAPI's
54
- # 'command-returns-exceptions', it can actually be anything.
55
- #
56
- # {'return': {}} is a QMPMessage,
57
- # {} is the QMPReturnValue.
58
-
59
-
60
- class QMPBadPortError(QMPError):
61
- """
62
- Unable to parse socket address: Port was non-numerical.
63
- """
64
-
65
-
66
- class QEMUMonitorProtocol:
67
- """
68
- Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP)
69
- and then allow to handle commands and events.
70
-
71
- :param address: QEMU address, can be a unix socket path (string), a tuple
72
- in the form ( address, port ) for a TCP connection, or an
73
- existing `socket.socket` object.
74
- :param server: Act as the socket server. (See 'accept')
75
- Not applicable when passing a socket directly.
76
- :param nickname: Optional nickname used for logging.
77
- """
78
-
79
- def __init__(self,
80
- address: Union[SocketAddrT, socket.socket],
81
- server: bool = False,
82
- nickname: Optional[str] = None):
83
-
84
- if server and isinstance(address, socket.socket):
85
- raise ValueError(
86
- "server argument should be False when passing a socket")
87
-
88
- self._qmp = QMPClient(nickname)
89
- self._aloop = asyncio.get_event_loop()
90
- self._address = address
91
- self._timeout: Optional[float] = None
92
-
93
- if server:
94
- assert not isinstance(self._address, socket.socket)
95
- self._sync(self._qmp.start_server(self._address))
96
-
97
- _T = TypeVar('_T')
98
-
99
- def _sync(
100
- self, future: Awaitable[_T], timeout: Optional[float] = None
101
- ) -> _T:
102
- return self._aloop.run_until_complete(
103
- asyncio.wait_for(future, timeout=timeout)
104
- )
105
-
106
- def _get_greeting(self) -> Optional[QMPMessage]:
107
- if self._qmp.greeting is not None:
108
- # pylint: disable=protected-access
109
- return self._qmp.greeting._asdict()
110
- return None
111
-
112
- def __enter__(self: _T) -> _T:
113
- # Implement context manager enter function.
114
- return self
115
-
116
- def __exit__(self,
117
- exc_type: Optional[Type[BaseException]],
118
- exc_val: Optional[BaseException],
119
- exc_tb: Optional[TracebackType]) -> None:
120
- # Implement context manager exit function.
121
- self.close()
122
-
123
- @classmethod
124
- def parse_address(cls, address: str) -> SocketAddrT:
125
- """
126
- Parse a string into a QMP address.
127
-
128
- Figure out if the argument is in the port:host form.
129
- If it's not, it's probably a file path.
130
- """
131
- components = address.split(':')
132
- if len(components) == 2:
133
- try:
134
- port = int(components[1])
135
- except ValueError:
136
- msg = f"Bad port: '{components[1]}' in '{address}'."
137
- raise QMPBadPortError(msg) from None
138
- return (components[0], port)
139
-
140
- # Treat as filepath.
141
- return address
142
-
143
- def connect(self, negotiate: bool = True) -> Optional[QMPMessage]:
144
- """
145
- Connect to the QMP Monitor and perform capabilities negotiation.
146
-
147
- :return: QMP greeting dict, or None if negotiate is false
148
- :raise ConnectError: on connection errors
149
- """
150
- self._qmp.await_greeting = negotiate
151
- self._qmp.negotiate = negotiate
152
-
153
- self._sync(
154
- self._qmp.connect(self._address)
155
- )
156
- return self._get_greeting()
157
-
158
- def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage:
159
- """
160
- Await connection from QMP Monitor and perform capabilities negotiation.
161
-
162
- :param timeout:
163
- timeout in seconds (nonnegative float number, or None).
164
- If None, there is no timeout, and this may block forever.
165
-
166
- :return: QMP greeting dict
167
- :raise ConnectError: on connection errors
168
- """
169
- self._qmp.await_greeting = True
170
- self._qmp.negotiate = True
171
-
172
- self._sync(self._qmp.accept(), timeout)
173
-
174
- ret = self._get_greeting()
175
- assert ret is not None
176
- return ret
177
-
178
- def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage:
179
- """
180
- Send a QMP command to the QMP Monitor.
181
-
182
- :param qmp_cmd: QMP command to be sent as a Python dict
183
- :return: QMP response as a Python dict
184
- """
185
- return dict(
186
- self._sync(
187
- # pylint: disable=protected-access
188
-
189
- # _raw() isn't a public API, because turning off
190
- # automatic ID assignment is discouraged. For
191
- # compatibility with iotests *only*, do it anyway.
192
- self._qmp._raw(qmp_cmd, assign_id=False),
193
- self._timeout
194
- )
195
- )
196
-
197
- def cmd_raw(self, name: str,
198
- args: Optional[Dict[str, object]] = None) -> QMPMessage:
199
- """
200
- Build a QMP command and send it to the QMP Monitor.
201
-
202
- :param name: command name (string)
203
- :param args: command arguments (dict)
204
- """
205
- qmp_cmd: QMPMessage = {'execute': name}
206
- if args:
207
- qmp_cmd['arguments'] = args
208
- return self.cmd_obj(qmp_cmd)
209
-
210
- def cmd(self, cmd: str, **kwds: object) -> QMPReturnValue:
211
- """
212
- Build and send a QMP command to the monitor, report errors if any
213
- """
214
- return self._sync(
215
- self._qmp.execute(cmd, kwds),
216
- self._timeout
217
- )
218
-
219
- def pull_event(self,
220
- wait: Union[bool, float] = False) -> Optional[QMPMessage]:
221
- """
222
- Pulls a single event.
223
-
224
- :param wait:
225
- If False or 0, do not wait. Return None if no events ready.
226
- If True, wait forever until the next event.
227
- Otherwise, wait for the specified number of seconds.
228
-
229
- :raise asyncio.TimeoutError:
230
- When a timeout is requested and the timeout period elapses.
231
-
232
- :return: The first available QMP event, or None.
233
- """
234
- if not wait:
235
- # wait is False/0: "do not wait, do not except."
236
- if self._qmp.events.empty():
237
- return None
238
-
239
- # If wait is 'True', wait forever. If wait is False/0, the events
240
- # queue must not be empty; but it still needs some real amount
241
- # of time to complete.
242
- timeout = None
243
- if wait and isinstance(wait, float):
244
- timeout = wait
245
-
246
- return dict(
247
- self._sync(
248
- self._qmp.events.get(),
249
- timeout
250
- )
251
- )
252
-
253
- def get_events(self, wait: Union[bool, float] = False) -> List[QMPMessage]:
254
- """
255
- Get a list of QMP events and clear all pending events.
256
-
257
- :param wait:
258
- If False or 0, do not wait. Return None if no events ready.
259
- If True, wait until we have at least one event.
260
- Otherwise, wait for up to the specified number of seconds for at
261
- least one event.
262
-
263
- :raise asyncio.TimeoutError:
264
- When a timeout is requested and the timeout period elapses.
265
-
266
- :return: A list of QMP events.
267
- """
268
- events = [dict(x) for x in self._qmp.events.clear()]
269
- if events:
270
- return events
271
-
272
- event = self.pull_event(wait)
273
- return [event] if event is not None else []
274
-
275
- def clear_events(self) -> None:
276
- """Clear current list of pending events."""
277
- self._qmp.events.clear()
278
-
279
- def close(self) -> None:
280
- """Close the connection."""
281
- self._sync(
282
- self._qmp.disconnect()
283
- )
284
-
285
- def settimeout(self, timeout: Optional[float]) -> None:
286
- """
287
- Set the timeout for QMP RPC execution.
288
-
289
- This timeout affects the `cmd`, `cmd_obj`, and `command` methods.
290
- The `accept`, `pull_event` and `get_event` methods have their
291
- own configurable timeouts.
292
-
293
- :param timeout:
294
- timeout in seconds, or None.
295
- None will wait indefinitely.
296
- """
297
- self._timeout = timeout
298
-
299
- def send_fd_scm(self, fd: int) -> None:
300
- """
301
- Send a file descriptor to the remote via SCM_RIGHTS.
302
- """
303
- self._qmp.send_fd_scm(fd)
304
-
305
- def __del__(self) -> None:
306
- if self._qmp.runstate == Runstate.IDLE:
307
- return
308
-
309
- if not self._aloop.is_running():
310
- self.close()
311
- else:
312
- # Garbage collection ran while the event loop was running.
313
- # Nothing we can do about it now, but if we don't raise our
314
- # own error, the user will be treated to a lot of traceback
315
- # they might not understand.
316
- raise QMPError(
317
- "QEMUMonitorProtocol.close()"
318
- " was not called before object was garbage collected"
319
- )
qemu/qmp/message.py DELETED
@@ -1,209 +0,0 @@
1
- """
2
- QMP Message Format
3
-
4
- This module provides the `Message` class, which represents a single QMP
5
- message sent to or from the server.
6
- """
7
-
8
- import json
9
- from json import JSONDecodeError
10
- from typing import (
11
- Dict,
12
- Iterator,
13
- Mapping,
14
- MutableMapping,
15
- Optional,
16
- Union,
17
- )
18
-
19
- from .error import ProtocolError
20
-
21
-
22
- class Message(MutableMapping[str, object]):
23
- """
24
- Represents a single QMP protocol message.
25
-
26
- QMP uses JSON objects as its basic communicative unit; so this
27
- Python object is a :py:obj:`~collections.abc.MutableMapping`. It may
28
- be instantiated from either another mapping (like a `dict`), or from
29
- raw `bytes` that still need to be deserialized.
30
-
31
- Once instantiated, it may be treated like any other MutableMapping::
32
-
33
- >>> msg = Message(b'{"hello": "world"}')
34
- >>> assert msg['hello'] == 'world'
35
- >>> msg['id'] = 'foobar'
36
- >>> print(msg)
37
- {
38
- "hello": "world",
39
- "id": "foobar"
40
- }
41
-
42
- It can be converted to `bytes`::
43
-
44
- >>> msg = Message({"hello": "world"})
45
- >>> print(bytes(msg))
46
- b'{"hello":"world","id":"foobar"}'
47
-
48
- Or back into a garden-variety `dict`::
49
-
50
- >>> dict(msg)
51
- {'hello': 'world'}
52
-
53
-
54
- :param value: Initial value, if any.
55
- :param eager:
56
- When `True`, attempt to serialize or deserialize the initial value
57
- immediately, so that conversion exceptions are raised during
58
- the call to ``__init__()``.
59
- """
60
- # pylint: disable=too-many-ancestors
61
-
62
- def __init__(self,
63
- value: Union[bytes, Mapping[str, object]] = b'{}', *,
64
- eager: bool = True):
65
- self._data: Optional[bytes] = None
66
- self._obj: Optional[Dict[str, object]] = None
67
-
68
- if isinstance(value, bytes):
69
- self._data = value
70
- if eager:
71
- self._obj = self._deserialize(self._data)
72
- else:
73
- self._obj = dict(value)
74
- if eager:
75
- self._data = self._serialize(self._obj)
76
-
77
- # Methods necessary to implement the MutableMapping interface, see:
78
- # https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping
79
-
80
- # We get pop, popitem, clear, update, setdefault, __contains__,
81
- # keys, items, values, get, __eq__ and __ne__ for free.
82
-
83
- def __getitem__(self, key: str) -> object:
84
- return self._object[key]
85
-
86
- def __setitem__(self, key: str, value: object) -> None:
87
- self._object[key] = value
88
- self._data = None
89
-
90
- def __delitem__(self, key: str) -> None:
91
- del self._object[key]
92
- self._data = None
93
-
94
- def __iter__(self) -> Iterator[str]:
95
- return iter(self._object)
96
-
97
- def __len__(self) -> int:
98
- return len(self._object)
99
-
100
- # Dunder methods not related to MutableMapping:
101
-
102
- def __repr__(self) -> str:
103
- if self._obj is not None:
104
- return f"Message({self._object!r})"
105
- return f"Message({bytes(self)!r})"
106
-
107
- def __str__(self) -> str:
108
- """Pretty-printed representation of this QMP message."""
109
- return json.dumps(self._object, indent=2)
110
-
111
- def __bytes__(self) -> bytes:
112
- """bytes representing this QMP message."""
113
- if self._data is None:
114
- self._data = self._serialize(self._obj or {})
115
- return self._data
116
-
117
- # Conversion Methods
118
-
119
- @property
120
- def _object(self) -> Dict[str, object]:
121
- """
122
- A `dict` representing this QMP message.
123
-
124
- Generated on-demand, if required. This property is private
125
- because it returns an object that could be used to invalidate
126
- the internal state of the `Message` object.
127
- """
128
- if self._obj is None:
129
- self._obj = self._deserialize(self._data or b'{}')
130
- return self._obj
131
-
132
- @classmethod
133
- def _serialize(cls, value: object) -> bytes:
134
- """
135
- Serialize a JSON object as `bytes`.
136
-
137
- :raise ValueError: When the object cannot be serialized.
138
- :raise TypeError: When the object cannot be serialized.
139
-
140
- :return: `bytes` ready to be sent over the wire.
141
- """
142
- return json.dumps(value, separators=(',', ':')).encode('utf-8')
143
-
144
- @classmethod
145
- def _deserialize(cls, data: bytes) -> Dict[str, object]:
146
- """
147
- Deserialize JSON `bytes` into a native Python `dict`.
148
-
149
- :raise DeserializationError:
150
- If JSON deserialization fails for any reason.
151
- :raise UnexpectedTypeError:
152
- If the data does not represent a JSON object.
153
-
154
- :return: A `dict` representing this QMP message.
155
- """
156
- try:
157
- obj = json.loads(data)
158
- except JSONDecodeError as err:
159
- emsg = "Failed to deserialize QMP message."
160
- raise DeserializationError(emsg, data) from err
161
- if not isinstance(obj, dict):
162
- raise UnexpectedTypeError(
163
- "QMP message is not a JSON object.",
164
- obj
165
- )
166
- return obj
167
-
168
-
169
- class DeserializationError(ProtocolError):
170
- """
171
- A QMP message was not understood as JSON.
172
-
173
- When this Exception is raised, ``__cause__`` will be set to the
174
- `json.JSONDecodeError` Exception, which can be interrogated for
175
- further details.
176
-
177
- :param error_message: Human-readable string describing the error.
178
- :param raw: The raw `bytes` that prompted the failure.
179
- """
180
- def __init__(self, error_message: str, raw: bytes):
181
- super().__init__(error_message)
182
- #: The raw `bytes` that were not understood as JSON.
183
- self.raw: bytes = raw
184
-
185
- def __str__(self) -> str:
186
- return "\n".join([
187
- super().__str__(),
188
- f" raw bytes were: {str(self.raw)}",
189
- ])
190
-
191
-
192
- class UnexpectedTypeError(ProtocolError):
193
- """
194
- A QMP message was JSON, but not a JSON object.
195
-
196
- :param error_message: Human-readable string describing the error.
197
- :param value: The deserialized JSON value that wasn't an object.
198
- """
199
- def __init__(self, error_message: str, value: object):
200
- super().__init__(error_message)
201
- #: The JSON value that was expected to be an object.
202
- self.value: object = value
203
-
204
- def __str__(self) -> str:
205
- strval = json.dumps(self.value, indent=2)
206
- return "\n".join([
207
- super().__str__(),
208
- f" json value was: {strval}",
209
- ])
qemu/qmp/models.py DELETED
@@ -1,146 +0,0 @@
1
- """
2
- QMP Data Models
3
-
4
- This module provides simplistic data classes that represent the few
5
- structures that the QMP spec mandates; they are used to verify incoming
6
- data to make sure it conforms to spec.
7
- """
8
- # pylint: disable=too-few-public-methods
9
-
10
- from collections import abc
11
- import copy
12
- from typing import (
13
- Any,
14
- Dict,
15
- Mapping,
16
- Optional,
17
- Sequence,
18
- )
19
-
20
-
21
- class Model:
22
- """
23
- Abstract data model, representing some QMP object of some kind.
24
-
25
- :param raw: The raw object to be validated.
26
- :raise KeyError: If any required fields are absent.
27
- :raise TypeError: If any required fields have the wrong type.
28
- """
29
- def __init__(self, raw: Mapping[str, Any]):
30
- self._raw = raw
31
-
32
- def _check_key(self, key: str) -> None:
33
- if key not in self._raw:
34
- raise KeyError(f"'{self._name}' object requires '{key}' member")
35
-
36
- def _check_value(self, key: str, type_: type, typestr: str) -> None:
37
- assert key in self._raw
38
- if not isinstance(self._raw[key], type_):
39
- raise TypeError(
40
- f"'{self._name}' member '{key}' must be a {typestr}"
41
- )
42
-
43
- def _check_member(self, key: str, type_: type, typestr: str) -> None:
44
- self._check_key(key)
45
- self._check_value(key, type_, typestr)
46
-
47
- @property
48
- def _name(self) -> str:
49
- return type(self).__name__
50
-
51
- def __repr__(self) -> str:
52
- return f"{self._name}({self._raw!r})"
53
-
54
-
55
- class Greeting(Model):
56
- """
57
- Defined in qmp-spec.rst, section "Server Greeting".
58
-
59
- :param raw: The raw Greeting object.
60
- :raise KeyError: If any required fields are absent.
61
- :raise TypeError: If any required fields have the wrong type.
62
- """
63
- def __init__(self, raw: Mapping[str, Any]):
64
- super().__init__(raw)
65
- #: 'QMP' member
66
- self.QMP: QMPGreeting # pylint: disable=invalid-name
67
-
68
- self._check_member('QMP', abc.Mapping, "JSON object")
69
- self.QMP = QMPGreeting(self._raw['QMP'])
70
-
71
- def _asdict(self) -> Dict[str, object]:
72
- """
73
- For compatibility with the iotests sync QMP wrapper.
74
-
75
- The legacy QMP interface needs Greetings as a garden-variety Dict.
76
-
77
- This interface is private in the hopes that it will be able to
78
- be dropped again in the near-future. Caller beware!
79
- """
80
- return dict(copy.deepcopy(self._raw))
81
-
82
-
83
- class QMPGreeting(Model):
84
- """
85
- Defined in qmp-spec.rst, section "Server Greeting".
86
-
87
- :param raw: The raw QMPGreeting object.
88
- :raise KeyError: If any required fields are absent.
89
- :raise TypeError: If any required fields have the wrong type.
90
- """
91
- def __init__(self, raw: Mapping[str, Any]):
92
- super().__init__(raw)
93
- #: 'version' member
94
- self.version: Mapping[str, object]
95
- #: 'capabilities' member
96
- self.capabilities: Sequence[object]
97
-
98
- self._check_member('version', abc.Mapping, "JSON object")
99
- self.version = self._raw['version']
100
-
101
- self._check_member('capabilities', abc.Sequence, "JSON array")
102
- self.capabilities = self._raw['capabilities']
103
-
104
-
105
- class ErrorResponse(Model):
106
- """
107
- Defined in qmp-spec.rst, section "Error".
108
-
109
- :param raw: The raw ErrorResponse object.
110
- :raise KeyError: If any required fields are absent.
111
- :raise TypeError: If any required fields have the wrong type.
112
- """
113
- def __init__(self, raw: Mapping[str, Any]):
114
- super().__init__(raw)
115
- #: 'error' member
116
- self.error: ErrorInfo
117
- #: 'id' member
118
- self.id: Optional[object] = None # pylint: disable=invalid-name
119
-
120
- self._check_member('error', abc.Mapping, "JSON object")
121
- self.error = ErrorInfo(self._raw['error'])
122
-
123
- if 'id' in raw:
124
- self.id = raw['id']
125
-
126
-
127
- class ErrorInfo(Model):
128
- """
129
- Defined in qmp-spec.rst, section "Error".
130
-
131
- :param raw: The raw ErrorInfo object.
132
- :raise KeyError: If any required fields are absent.
133
- :raise TypeError: If any required fields have the wrong type.
134
- """
135
- def __init__(self, raw: Mapping[str, Any]):
136
- super().__init__(raw)
137
- #: 'class' member, with an underscore to avoid conflicts in Python.
138
- self.class_: str
139
- #: 'desc' member
140
- self.desc: str
141
-
142
- self._check_member('class', str, "string")
143
- self.class_ = self._raw['class']
144
-
145
- self._check_member('desc', str, "string")
146
- self.desc = self._raw['desc']