Post-release version bump to 11.1.0
[libvirt-python.git] / generator.py
blobec6a41883f977cb5540081e87ec9bf4a64591672
1 #!/usr/bin/env python3
3 # generate python wrappers from the XML API description
6 import os
7 import re
8 import sys
9 import xml.sax
10 from contextlib import closing
11 from collections import defaultdict
12 from typing import Dict, IO, List, Optional, Set, Tuple, Union # noqa F401
13 ArgumentType = Tuple[str, str, str]
14 FunctionType = Tuple[str, ArgumentType, List[ArgumentType], str, str, str]
15 EnumValue = Union[str, int]
16 EnumType = Dict[str, EnumValue]
18 functions = {} # type: Dict[str, FunctionType]
19 enums = defaultdict(dict) # type: Dict[str, EnumType] # { enumType: { enumConstant: enumValue } }
20 event_ids = [] # type: List[str]
21 params = [] # type: List[Tuple[str, str]] # [ (paramName, paramValue)... ]
24 quiet = True
26 #######################################################################
28 # That part if purely the API acquisition phase from the
29 # libvirt API description
31 #######################################################################
32 debug = 0
33 onlyOverrides = False
34 sourceDir = "."
35 buildDir = "build"
37 libvirt_headers = [
38 "libvirt",
39 "libvirt-common",
40 "libvirt-domain",
41 "libvirt-domain-checkpoint",
42 "libvirt-domain-snapshot",
43 "libvirt-event",
44 "libvirt-host",
45 "libvirt-interface",
46 "libvirt-network",
47 "libvirt-nodedev",
48 "libvirt-nwfilter",
49 "libvirt-secret",
50 "libvirt-storage",
51 "libvirt-stream",
54 def openSourceFile(file: str, mode: str = "r", optional: bool = False):
55 path = os.path.join(sourceDir, file)
56 if optional and not os.path.exists(path):
57 return None
58 return open(path, mode)
60 def parse(data: IO[str]) -> None:
61 target = docParser()
62 with closing(xml.sax.make_parser()) as parser:
63 parser.setContentHandler(target)
64 parser.parse(data)
67 class docParser(xml.sax.handler.ContentHandler):
68 def __init__(self) -> None:
69 self._data = [] # type: List[str]
70 self.in_function = False
72 def characters(self, text: str) -> None:
73 if debug:
74 print("data %s" % text)
75 self._data.append(text)
77 def startElement(self, tag: str, attrs: Dict[str, str]) -> None:
78 if debug:
79 print("start %s, %s" % (tag, attrs))
80 if tag == 'function':
81 self._data = []
82 self.in_function = True
83 self.function_cond = ''
84 self.function_args = [] # type: List[ArgumentType]
85 self.function_descr = ''
86 self.function_return = None # type: Optional[ArgumentType]
87 self.function = attrs.get('name', '')
88 self.function_file = attrs.get('file', '')
89 self.function_module = attrs.get('module', '')
90 elif tag == 'cond':
91 self._data = []
92 elif tag == 'info':
93 self._data = []
94 elif tag == 'arg':
95 if self.in_function:
96 self.function_arg_name = attrs.get('name', '')
97 if self.function_arg_name == 'from':
98 self.function_arg_name = 'frm'
99 self.function_arg_type = attrs.get('type', '')
100 self.function_arg_info = attrs.get('info', '')
101 elif tag == 'return':
102 if self.in_function:
103 self.function_return_type = attrs.get('type', '')
104 self.function_return_info = attrs.get('info', '')
105 self.function_return_field = attrs.get('field', '')
106 elif tag == 'enum':
107 # enums come from header files, hence virterror.h
108 files = libvirt_headers + ["virerror",
109 "virterror",
110 "libvirt-lxc",
111 "libvirt-qemu"]
112 if attrs['file'] in files:
113 enum(attrs['type'], attrs['name'], attrs['value'])
114 elif tag == "macro":
115 if "string" in attrs:
116 params.append((attrs['name'], attrs['string']))
118 def endElement(self, tag: str) -> None:
119 if debug:
120 print("end %s" % tag)
121 if tag == 'function':
122 # functions come from source files, hence 'virerror.c'
123 if self.function:
124 assert self.function_return
126 modules = libvirt_headers + ["event",
127 "virevent",
128 "virerror",
129 "virterror",
130 "libvirt-lxc",
131 "libvirt-qemu"]
132 files = ["python", "python-lxc", "python-qemu"]
134 if (self.function_module in modules or
135 self.function_file in files):
136 function(self.function, self.function_descr,
137 self.function_return, self.function_args,
138 self.function_file, self.function_module,
139 self.function_cond)
140 self.in_function = False
141 elif tag == 'arg':
142 if self.in_function:
143 self.function_args.append((self.function_arg_name,
144 self.function_arg_type,
145 self.function_arg_info))
146 elif tag == 'return':
147 if self.in_function:
148 self.function_return = (self.function_return_type,
149 self.function_return_info,
150 self.function_return_field)
151 elif tag == 'info':
152 str = ''.join(self._data)
153 if self.in_function:
154 self.function_descr = str
155 elif tag == 'cond':
156 str = ''.join(self._data)
157 if self.in_function:
158 self.function_cond = str
161 def function(name: str, desc: str, ret: ArgumentType, args: List[ArgumentType], file: str, module: str, cond: str) -> None:
162 if onlyOverrides and name not in functions:
163 return
164 if name == "virConnectListDomains":
165 name = "virConnectListDomainsID"
166 functions[name] = (desc, ret, args, file, module, cond)
169 def enum(type: str, name: str, value: EnumValue) -> None:
170 if (name.startswith('VIR_DOMAIN_EVENT_ID_') or
171 name.startswith('VIR_NETWORK_EVENT_ID_')):
172 event_ids.append(name)
173 if value == 'VIR_TYPED_PARAM_INT':
174 value = 1
175 elif value == 'VIR_TYPED_PARAM_UINT':
176 value = 2
177 elif value == 'VIR_TYPED_PARAM_LLONG':
178 value = 3
179 elif value == 'VIR_TYPED_PARAM_ULLONG':
180 value = 4
181 elif value == 'VIR_TYPED_PARAM_DOUBLE':
182 value = 5
183 elif value == 'VIR_TYPED_PARAM_BOOLEAN':
184 value = 6
185 elif value == 'VIR_DOMAIN_AFFECT_CURRENT':
186 value = 0
187 elif value == 'VIR_DOMAIN_AFFECT_LIVE':
188 value = 1
189 elif value == 'VIR_DOMAIN_AFFECT_CONFIG':
190 value = 2
191 elif value == 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK':
192 value = -2
193 elif value == 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_DEFAULT':
194 value = -1
195 elif value == 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_NOWAIT':
196 value = 0
198 if onlyOverrides and name not in enums[type]:
199 return
200 enums[type][name] = value
203 #######################################################################
205 # Some filtering rules to drop functions/types which should not
206 # be exposed as-is on the Python interface
208 #######################################################################
210 skipped_types = {
211 # 'int *': "usually a return type",
212 'virConnectDomainEventCallback': "No function types in python",
213 'virConnectDomainEventGenericCallback': "No function types in python",
214 'virConnectDomainEventRTCChangeCallback': "No function types in python",
215 'virConnectDomainEventWatchdogCallback': "No function types in python",
216 'virConnectDomainEventIOErrorCallback': "No function types in python",
217 'virConnectDomainEventGraphicsCallback': "No function types in python",
218 'virConnectDomainQemuMonitorEventCallback': "No function types in python",
219 'virStreamEventCallback': "No function types in python",
220 'virEventHandleCallback': "No function types in python",
221 'virEventTimeoutCallback': "No function types in python",
222 'virDomainBlockJobInfoPtr': "Not implemented yet",
225 #######################################################################
227 # Table of remapping to/from the python type or class to the C
228 # counterpart.
230 #######################################################################
232 py_types = {
233 'void': ('', '', '', ''),
234 'int': ('i', '', "int", "int"),
235 'long': ('l', '', "long", "long"),
236 'double': ('d', '', "double", "double"),
237 'unsigned int': ('I', '', "int", "int"),
238 'unsigned long': ('l', '', "long", "long"),
239 'long long': ('L', '', "longlong", "long long"),
240 'unsigned long long': ('L', '', "longlong", "long long"),
241 'unsigned char *': ('z', '', "charPtr", "char *"),
242 'char *': ('z', '', "charPtr", "char *"),
243 'const char *': ('z', '', "constcharPtr", "const char *"),
244 'size_t': ('n', '', "size_t", "size_t"),
246 'virDomainPtr': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
247 'virDomain *': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
248 'const virDomain *': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
250 'virNetworkPtr': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
251 'virNetwork *': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
252 'const virNetwork *': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
254 'virNetworkPortPtr': ('O', "virNetworkPort", "virNetworkPortPtr", "virNetworkPortPtr"),
255 'virNetworkPort *': ('O', "virNetworkPort", "virNetworkPortPtr", "virNetworkPortPtr"),
256 'const virNetworkPort *': ('O', "virNetworkPort", "virNetworkPortPtr", "virNetworkPortPtr"),
258 'virInterfacePtr': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
259 'virInterface *': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
260 'const virInterface *': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
262 'virStoragePoolPtr': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
263 'virStoragePool *': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
264 'const virStoragePool *': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
266 'virStorageVolPtr': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
267 'virStorageVol *': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
268 'const virStorageVol *': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
270 'virConnectPtr': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
271 'virConnect *': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
272 'const virConnect *': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
274 'virNodeDevicePtr': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
275 'virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
276 'const virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
278 'virSecretPtr': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
279 'virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
280 'const virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
282 'virNWFilterPtr': ('O', "virNWFilter", "virNWFilterPtr", "virNWFilterPtr"),
283 'virNWFilter *': ('O', "virNWFilter", "virNWFilterPtr", "virNWFilterPtr"),
284 'const virNWFilter *': ('O', "virNWFilter", "virNWFilterPtr", "virNWFilterPtr"),
286 'virNWFilterBindingPtr': ('O', "virNWFilterBinding", "virNWFilterBindingPtr", "virNWFilterBindingPtr"),
287 'virNWFilterBinding *': ('O', "virNWFilterBinding", "virNWFilterBindingPtr", "virNWFilterBindingPtr"),
288 'const virNWFilterBinding *': ('O', "virNWFilterBinding", "virNWFilterBindingPtr", "virNWFilterBindingPtr"),
290 'virStreamPtr': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
291 'virStream *': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
292 'const virStream *': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
294 'virDomainCheckpointPtr': ('O', "virDomainCheckpoint", "virDomainCheckpointPtr", "virDomainCheckpointPtr"),
295 'virDomainCheckpoint *': ('O', "virDomainCheckpoint", "virDomainCheckpointPtr", "virDomainCheckpointPtr"),
296 'const virDomainCheckpoint *': ('O', "virDomainCheckpoint", "virDomainCheckpointPtr", "virDomainCheckpointPtr"),
298 'virDomainSnapshotPtr': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
299 'virDomainSnapshot *': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
300 'const virDomainSnapshot *': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
301 } # type: Dict[str, Tuple[str, str, str, str]]
304 #######################################################################
306 # This part writes the C <-> Python stubs libvirt.[ch] and
307 # the table libvirt-export.c.inc to add when registering the Python module
309 #######################################################################
311 # Class methods which are written by hand in libvirt.c but the Python-level
312 # code is still automatically generated (so they are not in skip_function()).
313 skip_impl = {
314 'virConnectGetVersion',
315 'virConnectGetLibVersion',
316 'virConnectListDomainsID',
317 'virConnectListDefinedDomains',
318 'virConnectListNetworks',
319 'virConnectListDefinedNetworks',
320 'virConnectListSecrets',
321 'virConnectListInterfaces',
322 'virConnectListStoragePools',
323 'virConnectListDefinedStoragePools',
324 'virConnectListStorageVols',
325 'virConnectListDefinedStorageVols',
326 'virConnectListDefinedInterfaces',
327 'virConnectListNWFilters',
328 'virDomainSnapshotListNames',
329 'virDomainSnapshotListChildrenNames',
330 'virConnGetLastError',
331 'virGetLastError',
332 'virDomainGetInfo',
333 'virDomainGetState',
334 'virDomainGetControlInfo',
335 'virDomainGetBlockInfo',
336 'virDomainGetJobInfo',
337 'virDomainGetJobStats',
338 'virNodeGetInfo',
339 'virNodeGetSecurityModel',
340 'virDomainGetSecurityLabel',
341 'virDomainGetSecurityLabelList',
342 'virDomainGetUUID',
343 'virDomainGetUUIDString',
344 'virDomainLookupByUUID',
345 'virNetworkGetUUID',
346 'virNetworkGetUUIDString',
347 'virNetworkLookupByUUID',
348 'virNetworkPortGetUUID',
349 'virNetworkPortGetUUIDString',
350 'virNetworkPortLookupByUUID',
351 'virDomainGetAutostart',
352 'virNetworkGetAutostart',
353 'virDomainBlockStats',
354 'virDomainInterfaceStats',
355 'virDomainMemoryStats',
356 'virNodeGetCellsFreeMemory',
357 'virDomainGetSchedulerType',
358 'virDomainGetSchedulerParameters',
359 'virDomainGetSchedulerParametersFlags',
360 'virDomainSetSchedulerParameters',
361 'virDomainSetSchedulerParametersFlags',
362 'virDomainSetBlkioParameters',
363 'virDomainGetBlkioParameters',
364 'virDomainSetMemoryParameters',
365 'virDomainGetMemoryParameters',
366 'virDomainSetNumaParameters',
367 'virDomainGetNumaParameters',
368 'virDomainGetVcpus',
369 'virDomainPinVcpu',
370 'virDomainPinVcpuFlags',
371 'virDomainGetVcpuPinInfo',
372 'virDomainGetEmulatorPinInfo',
373 'virDomainPinEmulator',
374 'virDomainGetIOThreadInfo',
375 'virDomainPinIOThread',
376 'virDomainSetIOThreadParams',
377 'virSecretGetValue',
378 'virSecretSetValue',
379 'virSecretGetUUID',
380 'virSecretGetUUIDString',
381 'virSecretLookupByUUID',
382 'virNWFilterGetUUID',
383 'virNWFilterGetUUIDString',
384 'virNWFilterLookupByUUID',
385 'virStoragePoolGetUUID',
386 'virStoragePoolGetUUIDString',
387 'virStoragePoolLookupByUUID',
388 'virStoragePoolGetInfo',
389 'virStorageVolGetInfo',
390 'virStorageVolGetInfoFlags',
391 'virStoragePoolGetAutostart',
392 'virStoragePoolListVolumes',
393 'virDomainBlockPeek',
394 'virDomainMemoryPeek',
395 'virEventRegisterImpl',
396 'virNodeListDevices',
397 'virNodeDeviceListCaps',
398 'virConnectBaselineCPU',
399 'virDomainRevertToSnapshot',
400 'virDomainSendKey',
401 'virNodeGetCPUStats',
402 'virNodeGetMemoryStats',
403 'virDomainGetBlockJobInfo',
404 'virDomainMigrateGetCompressionCache',
405 'virDomainMigrateGetMaxSpeed',
406 'virDomainMigrateGetMaxDowntime',
407 'virDomainBlockStatsFlags',
408 'virDomainSetBlockIoTune',
409 'virDomainGetBlockIoTune',
410 'virDomainSetInterfaceParameters',
411 'virDomainGetInterfaceParameters',
412 'virDomainGetCPUStats',
413 'virDomainGetDiskErrors',
414 'virNodeGetMemoryParameters',
415 'virNodeSetMemoryParameters',
416 'virConnectSetIdentity',
417 'virNodeGetCPUMap',
418 'virDomainMigrate3',
419 'virDomainMigrateToURI3',
420 'virConnectGetCPUModelNames',
421 'virNodeGetFreePages',
422 'virNetworkGetDHCPLeases',
423 'virDomainBlockCopy',
424 'virNodeAllocPages',
425 'virDomainGetFSInfo',
426 'virDomainInterfaceAddresses',
427 'virDomainGetPerfEvents',
428 'virDomainSetPerfEvents',
429 'virDomainGetGuestVcpus',
430 'virConnectBaselineHypervisorCPU',
431 'virDomainGetLaunchSecurityInfo',
432 'virDomainSetLaunchSecurityState',
433 'virNodeGetSEVInfo',
434 'virNetworkPortGetParameters',
435 'virNetworkPortSetParameters',
436 'virDomainGetGuestInfo',
437 'virDomainAuthorizedSSHKeysGet',
438 'virDomainAuthorizedSSHKeysSet',
439 'virDomainGetMessages',
440 'virNodeDeviceGetAutostart',
441 'virDomainSaveParams',
442 'virDomainRestoreParams',
444 'virDomainLxcOpenNamespace',
446 'virDomainQemuMonitorCommand',
447 'virDomainQemuAgentCommand',
451 # These are functions which the generator skips completely - no python
452 # or C code is generated. Generally should not be used for any more
453 # functions than those already listed
454 skip_function = {
455 'virConnectListDomains', # Python API is called virConnectListDomainsID for unknown reasons
456 'virConnSetErrorFunc', # Not used in Python API XXX is this a bug ?
457 'virResetError', # Not used in Python API XXX is this a bug ?
458 'virGetVersion', # Python C code is manually written
459 'virSetErrorFunc', # Python API is called virRegisterErrorHandler for unknown reasons
460 'virConnCopyLastError', # Python API is called virConnGetLastError instead
461 'virCopyLastError', # Python API is called virGetLastError instead
462 'virConnectOpenAuth', # Python C code is manually written
463 'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C
464 'virConnectDomainEventRegister', # overridden in virConnect.py
465 'virConnectDomainEventDeregister', # overridden in virConnect.py
466 'virConnectDomainEventRegisterAny', # overridden in virConnect.py
467 'virConnectDomainEventDeregisterAny', # overridden in virConnect.py
468 'virConnectNetworkEventRegisterAny', # overridden in virConnect.py
469 'virConnectNetworkEventDeregisterAny', # overridden in virConnect.py
470 'virConnectStoragePoolEventRegisterAny', # overridden in virConnect.py
471 'virConnectStoragePoolEventDeregisterAny', # overridden in virConnect.py
472 'virConnectNodeDeviceEventRegisterAny', # overridden in virConnect.py
473 'virConnectNodeDeviceEventDeregisterAny', # overridden in virConnect.py
474 'virConnectSecretEventRegisterAny', # overridden in virConnect.py
475 'virConnectSecretEventDeregisterAny', # overridden in virConnect.py
476 'virSaveLastError', # We have our own python error wrapper
477 'virFreeError', # Only needed if we use virSaveLastError
478 'virConnectListAllDomains', # overridden in virConnect.py
479 'virDomainListAllCheckpoints', # overridden in virDomain.py
480 'virDomainCheckpointListAllChildren', # overridden in virDomainCheckpoint.py
481 'virDomainListAllSnapshots', # overridden in virDomain.py
482 'virDomainSnapshotListAllChildren', # overridden in virDomainSnapshot.py
483 'virConnectListAllStoragePools', # overridden in virConnect.py
484 'virStoragePoolListAllVolumes', # overridden in virStoragePool.py
485 'virConnectListAllNetworks', # overridden in virConnect.py
486 'virNetworkListAllPorts', # overridden in virConnect.py
487 'virConnectListAllInterfaces', # overridden in virConnect.py
488 'virConnectListAllNodeDevices', # overridden in virConnect.py
489 'virConnectListAllNWFilters', # overridden in virConnect.py
490 'virConnectListAllNWFilterBindings', # overridden in virConnect.py
491 'virConnectListAllSecrets', # overridden in virConnect.py
492 'virConnectGetAllDomainStats', # overridden in virConnect.py
493 'virDomainListGetStats', # overridden in virConnect.py
494 'virDomainFDAssociate', # overridden in virDomain.py
496 'virStreamRecvAll', # Pure python libvirt-override-virStream.py
497 'virStreamSendAll', # Pure python libvirt-override-virStream.py
498 'virStreamRecv', # overridden in libvirt-override-virStream.py
499 'virStreamSend', # overridden in libvirt-override-virStream.py
500 'virStreamRecvHole', # overridden in libvirt-override-virStream.py
501 'virStreamSendHole', # overridden in libvirt-override-virStream.py
502 'virStreamRecvFlags', # overridden in libvirt-override-virStream.py
503 'virStreamSparseRecvAll', # overridden in libvirt-override-virStream.py
504 'virStreamSparseSendAll', # overridden in libvirt-override-virStream.py
506 'virConnectUnregisterCloseCallback', # overridden in virConnect.py
507 'virConnectRegisterCloseCallback', # overridden in virConnect.py
509 'virDomainCreateXMLWithFiles', # overridden in virConnect.py
510 'virDomainCreateWithFiles', # overridden in virDomain.py
512 'virDomainFSFreeze', # overridden in virDomain.py
513 'virDomainFSThaw', # overridden in virDomain.py
514 'virDomainGetTime', # overridden in virDomain.py
515 'virDomainSetTime', # overridden in virDomain.py
517 # 'Ref' functions have no use for bindings users.
518 "virConnectRef",
519 "virDomainRef",
520 "virInterfaceRef",
521 "virNetworkRef",
522 "virNetworkPortRef",
523 "virNodeDeviceRef",
524 "virSecretRef",
525 "virNWFilterRef",
526 "virNWFilterBindingRef",
527 "virStoragePoolRef",
528 "virStorageVolRef",
529 "virStreamRef",
530 "virDomainCheckpointRef",
531 "virDomainSnapshotRef",
533 # This functions shouldn't be called via the bindings (and even the docs
534 # contain an explicit warning to that effect). The equivalent should be
535 # implemented in pure python for each class
536 "virDomainGetConnect",
537 "virInterfaceGetConnect",
538 "virNetworkGetConnect",
539 "virNetworkPortGetNetwork",
540 "virSecretGetConnect",
541 "virNWFilterGetConnect",
542 "virStoragePoolGetConnect",
543 "virStorageVolGetConnect",
544 "virDomainCheckpointGetConnect",
545 "virDomainCheckpointGetDomain",
546 "virDomainSnapshotGetConnect",
547 "virDomainSnapshotGetDomain",
549 # only useful in C code, python code uses dict for typed parameters
550 "virTypedParamsAddBoolean",
551 "virTypedParamsAddDouble",
552 "virTypedParamsAddFromString",
553 "virTypedParamsAddInt",
554 "virTypedParamsAddLLong",
555 "virTypedParamsAddString",
556 "virTypedParamsAddUInt",
557 "virTypedParamsAddULLong",
558 "virTypedParamsClear",
559 "virTypedParamsFree",
560 "virTypedParamsGet",
561 "virTypedParamsGetBoolean",
562 "virTypedParamsGetDouble",
563 "virTypedParamsGetInt",
564 "virTypedParamsGetLLong",
565 "virTypedParamsGetString",
566 "virTypedParamsGetUInt",
567 "virTypedParamsGetULLong",
569 'virNetworkDHCPLeaseFree', # only useful in C, python code uses list
570 'virDomainStatsRecordListFree', # only useful in C, python uses dict
571 'virDomainFSInfoFree', # only useful in C, python code uses list
572 'virDomainIOThreadInfoFree', # only useful in C, python code uses list
573 'virDomainInterfaceFree', # only useful in C, python code uses list
575 "virDomainLxcEnterNamespace",
576 "virDomainLxcEnterSecurityLabel",
578 # "virDomainQemuAttach",
579 'virConnectDomainQemuMonitorEventRegister', # overridden in -qemu.py
580 'virConnectDomainQemuMonitorEventDeregister', # overridden in -qemu.py
581 'virDomainQemuMonitorCommandWithFiles', # overridden in -qemu.py
584 # Generate C code, but skip python impl
585 function_skip_python_impl = {
586 "virStreamFree", # Needed in custom virStream __del__, but free shouldn't
587 # be exposed in bindings
590 function_skip_index_one = {
591 "virDomainRevertToSnapshot",
595 def validate_function(name):
596 (desc, ret, args, file, mod, cond) = functions[name]
598 if name in skip_function:
599 return []
600 if name in skip_impl:
601 return []
603 failed = False
604 unknown = []
605 for a_name, a_type, a_info in args:
606 # This should be correct
607 if a_type[0:6] == "const ":
608 a_type = a_type[6:]
610 if a_type in skipped_types:
611 return []
613 if a_type not in py_types:
614 unknown.append(a_type)
616 r_type, r_info, r_field = ret
617 if r_type in skipped_types:
618 return []
619 if r_type != 'void' and r_type not in py_types:
620 unknown.append(r_type)
622 return unknown
625 def validate_functions():
626 unknown_types = defaultdict(list) # type: Dict[str, List[str]]
627 funcs_failed = [] # type: List[str]
629 for name in sorted(functions):
630 unknown = validate_function(name)
631 if unknown:
632 funcs_failed.append(name)
633 for thetype in unknown:
634 unknown_types[thetype].append(name)
636 if unknown_types:
637 print("Missing type converters: ")
638 for type, count in unknown_types.items():
639 print("%s:%d " % (type, len(count)))
641 for f in funcs_failed:
642 print("ERROR: failed %s" % f)
644 if funcs_failed:
645 return -1
647 return 0
650 def skip_both_impl(name: str) -> bool:
651 if name in skip_function:
652 return True
654 (desc, ret, args, file, mod, cond) = functions[name]
656 for a_name, a_type, a_info in args:
657 # This should be correct
658 if a_type[0:6] == "const ":
659 a_type = a_type[6:]
661 if a_type in skipped_types:
662 return True
664 r_type, r_info, r_field = ret
665 if r_type in skipped_types:
666 return True
668 return False
671 def skip_c_impl(name: str) -> bool:
672 if skip_both_impl(name):
673 return True
675 if name in skip_impl:
676 return True
678 return False
681 def skip_py_impl(name: str) -> bool:
682 if skip_both_impl(name):
683 return True
685 if name in function_skip_python_impl:
686 return True
688 return False
691 def print_function_wrapper(package: str, name: str, output: IO[str], export: IO[str], include: IO[str]) -> bool:
693 :returns: True if generated, False if skipped
695 (desc, ret, args, file, mod, cond) = functions[name]
697 if skip_c_impl(name):
698 return False
700 c_call = ""
701 format = ""
702 format_args = ""
703 c_args = ""
704 c_return = ""
705 c_convert = ""
706 num_bufs = 0
707 for a_name, a_type, a_info in args:
708 # This should be correct
709 if a_type[0:6] == "const ":
710 a_type = a_type[6:]
711 c_args += " %s %s;\n" % (a_type, a_name)
712 if a_type in py_types:
713 (f, t, n, c) = py_types[a_type]
714 if f:
715 format += f
716 if t:
717 format_args += ", &pyobj_%s" % (a_name)
718 c_args += " PyObject *pyobj_%s;\n" % (a_name)
719 c_convert += \
720 " %s = (%s) Py%s_Get(pyobj_%s);\n" % (
721 a_name, a_type, t, a_name)
722 else:
723 format_args += ", &%s" % (a_name)
724 if f == 't#':
725 format_args += ", &py_buffsize%d" % num_bufs
726 c_args += " int py_buffsize%d;\n" % num_bufs
727 num_bufs += 1
728 if c_call:
729 c_call += ", "
730 c_call += "%s" % (a_name)
731 else:
732 raise Exception("Unexpected type %s in function %s" % (a_type, name))
733 if format:
734 format += ":%s" % (name)
736 r_type, r_info, r_field = ret
737 if r_type == 'void':
738 if file == "python_accessor":
739 if args[1][1] == "char *":
740 c_call = "\n VIR_FREE(%s->%s);\n" % (
741 args[0][0], args[1][0])
742 c_call += " %s->%s = (%s)strdup((const xmlChar *)%s);\n" % (
743 args[0][0], args[1][0], args[1][1], args[1][0])
744 else:
745 c_call = "\n %s->%s = %s;\n" % (args[0][0], args[1][0],
746 args[1][0])
747 else:
748 c_call = "\n %s(%s);\n" % (name, c_call)
749 ret_convert = " Py_INCREF(Py_None);\n return Py_None;\n"
750 elif r_type in py_types:
751 (f, t, n, c) = py_types[r_type]
752 c_return = " %s c_retval;\n" % (r_type)
753 if file == "python_accessor" and r_field:
754 c_call = "\n c_retval = %s->%s;\n" % (args[0][0], r_field)
755 else:
756 c_call = "\n c_retval = %s(%s);\n" % (name, c_call)
757 ret_convert = " py_retval = libvirt_%sWrap((%s) c_retval);\n" % (n, c)
758 if n == "charPtr":
759 ret_convert += " free(c_retval);\n"
760 ret_convert += " return py_retval;\n"
761 else:
762 raise Exception("Unexpected type %s in function %s" % (r_type, name))
764 if cond:
765 include.write("#if %s\n" % cond)
766 export.write("#if %s\n" % cond)
767 output.write("#if %s\n" % cond)
769 include.write("PyObject * ")
770 include.write("%s_%s(PyObject *self, PyObject *args);\n" % (package, name))
771 export.write(" { (char *)\"%s\", %s_%s, METH_VARARGS, NULL },\n" %
772 (name, package, name))
774 if file == "python":
775 # Those have been manually generated
776 if cond:
777 include.write("#endif\n")
778 export.write("#endif\n")
779 output.write("#endif\n")
780 return True
781 if file == "python_accessor" and r_type != "void" and not r_field:
782 # Those have been manually generated
783 if cond:
784 include.write("#endif\n")
785 export.write("#endif\n")
786 output.write("#endif\n")
787 return True
789 output.write("PyObject *\n")
790 output.write("%s_%s(PyObject *self ATTRIBUTE_UNUSED," % (package, name))
791 output.write(" PyObject *args")
792 if format == "":
793 output.write(" ATTRIBUTE_UNUSED")
794 output.write(") {\n")
795 if r_type != 'void':
796 output.write(" PyObject *py_retval;\n")
797 if c_return:
798 output.write(c_return)
799 if c_args:
800 output.write(c_args)
801 if format:
802 output.write("\n if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" %
803 (format, format_args))
804 output.write(" return NULL;\n")
805 if c_convert:
806 output.write(c_convert + "\n")
808 output.write(" LIBVIRT_BEGIN_ALLOW_THREADS;")
809 output.write(c_call)
810 output.write(" LIBVIRT_END_ALLOW_THREADS;\n")
811 output.write(ret_convert)
812 output.write("}\n\n")
813 if cond:
814 include.write("#endif /* %s */\n" % cond)
815 export.write("#endif /* %s */\n" % cond)
816 output.write("#endif /* %s */\n" % cond)
818 return True
821 def print_c_pointer(classname: str, output: IO[str], export: IO[str], include: IO[str]) -> None:
822 output.write("PyObject *\n")
823 output.write("libvirt_%s_pointer(PyObject *self ATTRIBUTE_UNUSED, PyObject *args)\n" % classname)
824 output.write("{\n")
825 output.write(" %sPtr ptr;\n" % classname)
826 output.write(" PyObject *pyptr;\n")
827 output.write(" PyObject *pylong;\n")
828 output.write("\n")
829 output.write(" if (!PyArg_ParseTuple(args, (char *) \"O\", &pyptr))\n")
830 output.write(" return NULL;\n")
831 output.write(" ptr = (%sPtr) Py%s_Get(pyptr);\n" % (classname, classname))
832 output.write(" pylong = PyLong_FromVoidPtr(ptr);\n")
833 output.write(" return pylong;\n")
834 output.write("}\n")
835 output.write("\n")
837 include.write("PyObject *libvirt_%s_pointer(PyObject *self, PyObject *args);\n" % classname)
839 export.write(" { (char *)\"%s_pointer\", libvirt_%s_pointer, METH_VARARGS, NULL },\n" %
840 (classname, classname))
843 def load_apis(module: str, api_xml: str):
844 global onlyOverrides
846 try:
847 onlyOverrides = False
848 with open(api_xml) as stream:
849 parse(stream)
850 except IOError as msg:
851 print(api_xml, ":", msg)
852 sys.exit(1)
854 n = len(functions)
855 if not quiet:
856 print("Found %d functions in %s" % ((n), api_xml))
858 override_api_xml = "%s-override-api.xml" % module
859 py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
861 try:
862 onlyOverrides = True
863 with openSourceFile(override_api_xml) as stream:
864 parse(stream)
865 except IOError as msg:
866 print(override_api_xml, ":", msg)
868 if not quiet:
869 # XXX: This is not right, same function already in @functions
870 # will be overwritten.
871 print("Found %d functions in %s" % (len(functions) - n, override_api_xml))
874 def emit_c_code(module: str) -> None:
875 package = module.replace('-', '_')
877 nb_wrap = 0
879 header_file = "%s/%s.h" % (buildDir, module)
880 export_file = "%s/%s-export.c.inc" % (buildDir, module)
881 wrapper_file = "%s/%s.c" % (buildDir, module)
883 include = open(header_file, "w")
884 include.write("/* Generated by generator.py */\n\n")
886 export = open(export_file, "w")
887 export.write("/* Generated by generator.py */\n\n")
889 wrapper = open(wrapper_file, "w")
890 wrapper.write("/* Generated by generator.py */\n\n")
891 wrapper.write("#include <stdlib.h>\n")
892 wrapper.write("#include <Python.h>\n")
893 wrapper.write("#include <libvirt/%s.h>\n" % (module,))
894 wrapper.write("#include \"typewrappers.h\"\n")
895 wrapper.write("#include \"%s.h\"\n\n" % (module))
897 for function in sorted(functions):
898 if print_function_wrapper(package, function, wrapper, export, include):
899 nb_wrap += 1
901 if module == "libvirt":
902 # Write C pointer conversion functions.
903 for classname in primary_classes:
904 print_c_pointer(classname, wrapper, export, include)
905 # Write define wrappers around event id enums, so that the
906 # preprocessor can see which enums were available.
907 for event_id in event_ids:
908 include.write("#define %s %s\n" % (event_id, event_id))
910 include.close()
911 export.close()
912 wrapper.close()
914 if not quiet:
915 print("Generated %d wrapper functions" % nb_wrap)
918 #######################################################################
920 # This part writes part of the Python front-end classes based on
921 # mapping rules between types and classes and also based on function
922 # renaming to get consistent function names at the Python level
924 #######################################################################
927 # The type automatically remapped to generated classes
928 # "C-type" -> (accessor, create, class, parent-class)
930 classes_type = {
931 "virDomainPtr": ("._o", "virDomain(%(p)s, _obj=%(o)s)", "virDomain", "virConnect"),
932 "virDomain *": ("._o", "virDomain(%(p)s, _obj=%(o)s)", "virDomain", "virConnect"),
933 "virNetworkPtr": ("._o", "virNetwork(%(p)s, _obj=%(o)s)", "virNetwork", "virConnect"),
934 "virNetwork *": ("._o", "virNetwork(%(p)s, _obj=%(o)s)", "virNetwork", "virConnect"),
935 "virNetworkPortPtr": ("._o", "virNetworkPort(%(p)s, _obj=%(o)s)", "virNetworkPort", "virNetwork"),
936 "virNetworkPort *": ("._o", "virNetworkPort(%(p)s, _obj=%(o)s)", "virNetworkPort", "virNetwork"),
937 "virInterfacePtr": ("._o", "virInterface(%(p)s, _obj=%(o)s)", "virInterface", "virConnect"),
938 "virInterface *": ("._o", "virInterface(%(p)s, _obj=%(o)s)", "virInterface", "virConnect"),
939 "virStoragePoolPtr": ("._o", "virStoragePool(%(p)s, _obj=%(o)s)", "virStoragePool", "virConnect"),
940 "virStoragePool *": ("._o", "virStoragePool(%(p)s, _obj=%(o)s)", "virStoragePool", "virConnect"),
941 "virStorageVolPtr": ("._o", "virStorageVol(%(p)s, _obj=%(o)s)", "virStorageVol", "virConnect"),
942 "virStorageVol *": ("._o", "virStorageVol(%(p)s, _obj=%(o)s)", "virStorageVol", "virConnect"),
943 "virNodeDevicePtr": ("._o", "virNodeDevice(%(p)s, _obj=%(o)s)", "virNodeDevice", "virConnect"),
944 "virNodeDevice *": ("._o", "virNodeDevice(%(p)s, _obj=%(o)s)", "virNodeDevice", "virConnect"),
945 "virSecretPtr": ("._o", "virSecret(%(p)s, _obj=%(o)s)", "virSecret", "virConnect"),
946 "virSecret *": ("._o", "virSecret(%(p)s, _obj=%(o)s)", "virSecret", "virConnect"),
947 "virNWFilterPtr": ("._o", "virNWFilter(%(p)s, _obj=%(o)s)", "virNWFilter", "virConnect"),
948 "virNWFilter *": ("._o", "virNWFilter(%(p)s, _obj=%(o)s)", "virNWFilter", "virConnect"),
949 "virNWFilterBindingPtr": ("._o", "virNWFilterBinding(%(p)s, _obj=%(o)s)", "virNWFilterBinding", "virConnect"),
950 "virNWFilterBinding *": ("._o", "virNWFilterBinding(%(p)s, _obj=%(o)s)", "virNWFilterBinding", "virConnect"),
951 "virStreamPtr": ("._o", "virStream(%(p)s, _obj=%(o)s)", "virStream", "virConnect"),
952 "virStream *": ("._o", "virStream(%(p)s, _obj=%(o)s)", "virStream", "virConnect"),
953 "virConnectPtr": ("._o", "virConnect(_obj=%(o)s)", "virConnect", ""),
954 "virConnect *": ("._o", "virConnect(_obj=%(o)s)", "virConnect", ""),
955 "virDomainCheckpointPtr": ("._o", "virDomainCheckpoint(%(p)s, _obj=%(o)s)", "virDomainCheckpoint", "virDomain"),
956 "virDomainCheckpoint *": ("._o", "virDomainCheckpoint(%(p)s, _obj=%(o)s)", "virDomainCheckpoint", "virDomain"),
957 "virDomainSnapshotPtr": ("._o", "virDomainSnapshot(%(p)s, _obj=%(o)s)", "virDomainSnapshot", "virDomain"),
958 "virDomainSnapshot *": ("._o", "virDomainSnapshot(%(p)s, _obj=%(o)s)", "virDomainSnapshot", "virDomain"),
961 primary_classes = ["virDomain", "virNetwork", "virNetworkPort",
962 "virInterface", "virStoragePool", "virStorageVol",
963 "virConnect", "virNodeDevice", "virSecret",
964 "virNWFilter", "virNWFilterBinding",
965 "virStream", "virDomainCheckpoint", "virDomainSnapshot"]
967 classes_destructors = {
968 "virDomain": "virDomainFree",
969 "virNetwork": "virNetworkFree",
970 "virNetworkPort": "virNetworkPortFree",
971 "virInterface": "virInterfaceFree",
972 "virStoragePool": "virStoragePoolFree",
973 "virStorageVol": "virStorageVolFree",
974 "virNodeDevice": "virNodeDeviceFree",
975 "virSecret": "virSecretFree",
976 "virNWFilter": "virNWFilterFree",
977 "virNWFilterBinding": "virNWFilterBindingFree",
978 "virDomainCheckpoint": "virDomainCheckpointFree",
979 "virDomainSnapshot": "virDomainSnapshotFree",
980 # We hand-craft __del__ for this one
981 # "virStream": "virStreamFree",
984 class_skip_connect_impl = {
985 "virConnect",
988 class_domain_impl = {
989 "virDomainCheckpoint",
990 "virDomainSnapshot",
993 class_network_impl = {
994 "virNetworkPort",
997 functions_noexcept = {
998 'virDomainGetID',
999 'virDomainGetName',
1000 'virNetworkGetName',
1001 'virInterfaceGetName',
1002 'virStoragePoolGetName',
1003 'virStorageVolGetName',
1004 'virStorageVolGetkey',
1005 'virNodeDeviceGetName',
1006 'virNodeDeviceGetParent',
1007 'virSecretGetUsageType',
1008 'virSecretGetUsageID',
1009 'virNWFilterGetName',
1010 'virNWFilterBindingGetFilterName',
1011 'virNWFilterBindingGetPortDev',
1014 function_classes = {
1015 "None": []
1016 } # type: Dict[str, List[Tuple[int, str, str, ArgumentType, List[ArgumentType], str, str]]]
1018 # Functions returning an integral type which need special rules to
1019 # check for errors and raise exceptions.
1020 functions_int_exception_test = {
1021 'virDomainGetMaxMemory': "%s == 0",
1023 functions_int_default_test = "%s == -1"
1026 def is_integral_type(name: str) -> bool:
1027 return re.search("^(unsigned)? ?(int|long)$", name) is not None
1030 def is_optional_arg(info: str) -> bool:
1031 return re.search(r"^\(?optional\)?", info) is not None
1034 def is_python_noninteger_type(name: str) -> bool:
1035 return name[-1:] == "*"
1038 def nameFixup(name: str, classe: str, type: str, file: str) -> str:
1039 # avoid a disastrous clash
1040 listname = classe + "List"
1041 l = len(classe)
1042 if name[0:l] == listname:
1043 func = name[l:]
1044 func = func[0:1].lower() + func[1:]
1045 elif name[0:16] == "virNetworkDefine":
1046 func = name[3:]
1047 func = func[0:1].lower() + func[1:]
1048 elif name[0:19] == "virNetworkCreateXML":
1049 func = name[3:]
1050 func = func[0:1].lower() + func[1:]
1051 elif name[0:16] == "virNetworkLookup":
1052 func = name[3:]
1053 func = func[0:1].lower() + func[1:]
1054 elif name[0:23] == "virNetworkPortCreateXML":
1055 func = name[10:]
1056 func = func[0:1].lower() + func[1:]
1057 elif name[0:20] == "virNetworkPortLookup":
1058 func = name[10:]
1059 func = func[0:1].lower() + func[1:]
1060 elif name[0:18] == "virInterfaceDefine":
1061 func = name[3:]
1062 func = func[0:1].lower() + func[1:]
1063 elif name[0:21] == "virInterfaceCreateXML":
1064 func = name[3:]
1065 func = func[0:1].lower() + func[1:]
1066 elif name[0:18] == "virInterfaceLookup":
1067 func = name[3:]
1068 func = func[0:1].lower() + func[1:]
1069 elif name[0:15] == "virSecretDefine":
1070 func = name[3:]
1071 func = func[0:1].lower() + func[1:]
1072 elif name[0:15] == "virSecretLookup":
1073 func = name[3:]
1074 func = func[0:1].lower() + func[1:]
1075 elif name[0:27] == "virNWFilterBindingCreateXML":
1076 func = name[3:]
1077 func = func[0:3].lower() + func[3:]
1078 elif name[0:24] == "virNWFilterBindingLookup":
1079 func = name[3:]
1080 func = func[0:3].lower() + func[3:]
1081 elif name[0:24] == "virNWFilterBindingDefine":
1082 func = name[3:]
1083 func = func[0:3].lower() + func[3:]
1084 elif name[0:24] == "virNWFilterBindingLookup":
1085 func = name[3:]
1086 func = func[0:3].lower() + func[3:]
1087 elif name[0:17] == "virNWFilterDefine":
1088 func = name[3:]
1089 func = func[0:3].lower() + func[3:]
1090 elif name[0:17] == "virNWFilterLookup":
1091 func = name[3:]
1092 func = func[0:3].lower() + func[3:]
1093 elif name[0:20] == "virStoragePoolDefine":
1094 func = name[3:]
1095 func = func[0:1].lower() + func[1:]
1096 elif name[0:23] == "virStoragePoolCreateXML":
1097 func = name[3:]
1098 func = func[0:1].lower() + func[1:]
1099 elif name[0:20] == "virStoragePoolLookup":
1100 func = name[3:]
1101 func = func[0:1].lower() + func[1:]
1102 elif name[0:19] == "virStorageVolDefine":
1103 func = name[3:]
1104 func = func[0:1].lower() + func[1:]
1105 elif name[0:19] == "virStorageVolLookup":
1106 func = name[3:]
1107 func = func[0:1].lower() + func[1:]
1108 elif name[0:20] == "virDomainGetCPUStats":
1109 func = name[9:]
1110 func = func[0:1].lower() + func[1:]
1111 elif name[0:24] == "virDomainGetIOThreadInfo":
1112 func = name[12:]
1113 func = func[0:2].lower() + func[2:]
1114 elif name[0:18] == "virDomainGetFSInfo":
1115 func = name[12:]
1116 func = func[0:2].lower() + func[2:]
1117 elif name[0:12] == "virDomainGet":
1118 func = name[12:]
1119 func = func[0:1].lower() + func[1:]
1120 elif name[0:31] == "virDomainCheckpointLookupByName":
1121 func = name[9:]
1122 func = func[0:1].lower() + func[1:]
1123 elif name[0:28] == "virDomainCheckpointCreateXML":
1124 func = name[9:]
1125 func = func[0:1].lower() + func[1:]
1126 elif name[0:19] == "virDomainCheckpoint":
1127 func = name[19:]
1128 func = func[0:1].lower() + func[1:]
1129 elif name[0:29] == "virDomainSnapshotLookupByName":
1130 func = name[9:]
1131 func = func[0:1].lower() + func[1:]
1132 elif name[0:26] == "virDomainSnapshotListNames":
1133 func = name[9:]
1134 func = func[0:1].lower() + func[1:]
1135 elif name[0:28] == "virDomainSnapshotNumChildren":
1136 func = name[17:]
1137 func = func[0:1].lower() + func[1:]
1138 elif name[0:20] == "virDomainSnapshotNum":
1139 func = name[9:]
1140 func = func[0:1].lower() + func[1:]
1141 elif name[0:26] == "virDomainSnapshotCreateXML":
1142 func = name[9:]
1143 func = func[0:1].lower() + func[1:]
1144 elif name[0:24] == "virDomainSnapshotCurrent":
1145 func = name[9:]
1146 func = func[0:1].lower() + func[1:]
1147 elif name[0:17] == "virDomainSnapshot":
1148 func = name[17:]
1149 func = func[0:1].lower() + func[1:]
1150 elif name[0:9] == "virDomain":
1151 func = name[9:]
1152 func = func[0:1].lower() + func[1:]
1153 elif name[0:17] == "virNetworkPortGet":
1154 func = name[17:]
1155 func = func[0:1].lower() + func[1:]
1156 elif name[0:13] == "virNetworkGet":
1157 func = name[13:]
1158 func = func[0:1].lower() + func[1:]
1159 func = func.replace("dHCP", "DHCP")
1160 elif name[0:14] == "virNetworkPort":
1161 func = name[14:]
1162 func = func[0:1].lower() + func[1:]
1163 elif name[0:10] == "virNetwork":
1164 func = name[10:]
1165 func = func[0:1].lower() + func[1:]
1166 elif name[0:15] == "virInterfaceGet":
1167 func = name[15:]
1168 func = func[0:1].lower() + func[1:]
1169 elif name[0:12] == "virInterface":
1170 func = name[12:]
1171 func = func[0:1].lower() + func[1:]
1172 elif name[0:12] == 'virSecretGet':
1173 func = name[12:]
1174 func = func[0:1].lower() + func[1:]
1175 elif name[0:9] == 'virSecret':
1176 func = name[9:]
1177 func = func[0:1].lower() + func[1:]
1178 elif name[0:21] == 'virNWFilterBindingGet':
1179 func = name[21:]
1180 func = func[0:1].lower() + func[1:]
1181 elif name[0:18] == 'virNWFilterBinding':
1182 func = name[18:]
1183 func = func[0:1].lower() + func[1:]
1184 elif name[0:14] == 'virNWFilterGet':
1185 func = name[14:]
1186 func = func[0:1].lower() + func[1:]
1187 elif name[0:11] == 'virNWFilter':
1188 func = name[11:]
1189 func = func[0:1].lower() + func[1:]
1190 elif name[0:12] == 'virStreamNew':
1191 func = "newStream"
1192 elif name[0:9] == 'virStream':
1193 func = name[9:]
1194 func = func[0:1].lower() + func[1:]
1195 elif name[0:17] == "virStoragePoolGet":
1196 func = name[17:]
1197 func = func[0:1].lower() + func[1:]
1198 elif name[0:14] == "virStoragePool":
1199 func = name[14:]
1200 func = func[0:1].lower() + func[1:]
1201 elif name[0:16] == "virStorageVolGet":
1202 func = name[16:]
1203 func = func[0:1].lower() + func[1:]
1204 elif name[0:13] == "virStorageVol":
1205 func = name[13:]
1206 func = func[0:1].lower() + func[1:]
1207 elif name[0:16] == "virNodeDeviceGet":
1208 func = name[16].lower() + name[17:]
1209 elif name[0:19] == "virNodeDeviceLookup":
1210 func = name[3].lower() + name[4:]
1211 elif name[0:22] == "virNodeDeviceCreateXML":
1212 func = name[3].lower() + name[4:]
1213 elif name[0:19] == "virNodeDeviceDefine":
1214 func = name[3].lower() + name[4:]
1215 elif name[0:13] == "virNodeDevice":
1216 func = name[13].lower() + name[14:]
1217 elif name[0:7] == "virNode":
1218 func = name[7:]
1219 func = func[0:1].lower() + func[1:]
1220 elif name[0:10] == "virConnect":
1221 func = name[10:]
1222 func = func[0:1].lower() + func[1:]
1223 elif name[0:3] == "xml":
1224 func = name[3:]
1225 func = func[0:1].lower() + func[1:]
1226 else:
1227 func = name
1228 if func == "iD":
1229 func = "ID"
1230 if func == "uUID":
1231 func = "UUID"
1232 if func == "uUIDString":
1233 func = "UUIDString"
1234 if func == "oSType":
1235 func = "OSType"
1236 if func == "xMLDesc":
1237 func = "XMLDesc"
1238 if func == "mACString":
1239 func = "MACString"
1241 return func
1244 def functionSortKey(info: Tuple) -> Tuple[str, str]:
1245 (index, func, name, ret, args, filename, mod) = info
1246 return func, filename
1249 def writeDoc(module: str, name: str, args: List[ArgumentType], indent: str, output: IO) -> None:
1250 if not functions[name][0]:
1251 return
1252 val = functions[name][0]
1253 val = val.replace("NULL", "None")
1254 sep = '\n%s' % (indent,)
1255 output.write('%s"""%s """\n' % (indent, sep.join(val.splitlines())))
1258 def emit_py_code(module: str) -> None:
1259 package = module.replace('-', '_')
1260 if module == "libvirt":
1261 pymod = "libvirtmod"
1262 cygmod = "cygvirtmod"
1263 elif module == "libvirt-lxc":
1264 pymod = "libvirtmod_lxc"
1265 cygmod = "cygvirtmod_lxc"
1266 elif module == "libvirt-qemu":
1267 pymod = "libvirtmod_qemu"
1268 cygmod = "cygvirtmod_qemu"
1269 else:
1270 raise Exception("Unknown module '%s'" % module)
1272 for tinfo in classes_type.values():
1273 function_classes[tinfo[2]] = []
1276 # Build the list of C types to look for ordered to start
1277 # with primary classes
1279 ctypes = [] # type: List[str]
1280 classes_list = [] # type: List[str]
1281 ctypes_processed = set() # type: Set[str]
1282 classes_processed = set() # type: Set[str]
1283 for classe in primary_classes:
1284 classes_list.append(classe)
1285 classes_processed.add(classe)
1286 for type, tinfo in classes_type.items():
1287 if tinfo[2] == classe:
1288 ctypes.append(type)
1289 ctypes_processed.add(type)
1290 for type, tinfo in classes_type.items():
1291 if type in ctypes_processed:
1292 continue
1293 if tinfo[2] not in classes_processed:
1294 classes_list.append(tinfo[2])
1295 classes_processed.add(tinfo[2])
1297 ctypes.append(type)
1298 ctypes_processed.add(type)
1300 for name, (desc, ret, args, file, mod, cond) in functions.items():
1301 if skip_py_impl(name):
1302 continue
1304 for type in ctypes:
1305 classe = classes_type[type][2]
1307 if name[0:3] == "vir" and len(args) >= 1 and args[0][1] == type:
1308 func = nameFixup(name, classe, type, file)
1309 info = (0, func, name, ret, args, file, mod)
1310 function_classes[classe].append(info)
1311 break
1312 elif name[0:3] == "vir" and len(args) >= 2 and args[1][1] == type \
1313 and file != "python_accessor" and name not in function_skip_index_one:
1314 func = nameFixup(name, classe, type, file)
1315 info = (1, func, name, ret, args, file, mod)
1316 function_classes[classe].append(info)
1317 break
1318 else:
1319 func = nameFixup(name, "None", file, file)
1320 info = (0, func, name, ret, args, file, mod)
1321 function_classes['None'].append(info)
1323 classes_file = "%s/%s.py" % (buildDir, package)
1324 extra_file = "%s-override.py" % module
1325 extra = openSourceFile(extra_file, "r", True)
1327 classes = open(classes_file, "w")
1329 classes.write("#\n")
1330 classes.write("# WARNING WARNING WARNING WARNING\n")
1331 classes.write("#\n")
1332 classes.write("# This file is automatically written by generator.py. Any changes\n")
1333 classes.write("# made here will be lost.\n")
1334 classes.write("#\n")
1335 classes.write("# To change the manually written methods edit %s-override.py\n" % (module,))
1336 classes.write("# To change the automatically written methods edit generator.py\n")
1337 classes.write("#\n")
1338 classes.write("# WARNING WARNING WARNING WARNING\n")
1339 classes.write("#\n")
1340 classes.write("try:\n")
1341 classes.write(" import %s # type: ignore\n" % pymod)
1342 classes.write("except ImportError as lib_e:\n")
1343 classes.write(" try:\n")
1344 classes.write(" import %s as %s # type: ignore\n" % (cygmod, pymod))
1345 classes.write(" except ImportError as cyg_e:\n")
1346 classes.write(" if \"No module named\" in str(cyg_e):\n")
1347 classes.write(" raise lib_e\n\n")
1349 if module != "libvirt":
1350 classes.write("import libvirt\n")
1351 classes.write("\n")
1353 if extra:
1354 classes.write("# WARNING WARNING WARNING WARNING\n")
1355 classes.write("#\n")
1356 classes.write("# Manually written part of python bindings for %s\n" % module)
1357 classes.writelines(extra.readlines())
1358 classes.write("#\n")
1359 classes.write("# WARNING WARNING WARNING WARNING\n")
1360 classes.write("#\n")
1361 classes.write("# Automatically written part of python bindings for %s\n" % module)
1362 classes.write("#\n")
1363 classes.write("# WARNING WARNING WARNING WARNING\n")
1364 if extra:
1365 extra.close()
1367 if "None" in function_classes:
1368 flist = function_classes["None"]
1369 oldfile = ""
1370 for (index, func, name, ret, args, file, mod) in sorted(flist, key=functionSortKey):
1371 if file != oldfile:
1372 classes.write("#\n# Functions from module %s\n#\n\n" % file)
1373 oldfile = file
1374 classes.write("def %s(" % func)
1375 for n, (a_name, a_type, a_info) in enumerate(args):
1376 if n != 0:
1377 classes.write(", ")
1378 classes.write("%s" % a_name)
1379 if a_name == "flags" or is_optional_arg(a_info):
1380 if is_integral_type(a_type):
1381 classes.write("=0")
1382 else:
1383 classes.write("=None")
1384 classes.write("):\n")
1385 writeDoc(module, name, args, ' ', classes)
1387 for a_name, a_type, a_info in args:
1388 if a_type in classes_type:
1389 classes.write(" if %s is None:\n"
1390 " %s__o = None\n" %
1391 (a_name, a_name))
1392 classes.write(" else:\n"
1393 " %s__o = %s%s\n" %
1394 (a_name, a_name, classes_type[a_type][0]))
1396 r_type, r_info, r_field = ret
1397 if r_type != "void":
1398 classes.write(" ret = ")
1399 else:
1400 classes.write(" ")
1401 classes.write("%s.%s(" % (pymod, name))
1402 for n, (a_name, a_type, a_info) in enumerate(args):
1403 if n != 0:
1404 classes.write(", ")
1405 classes.write("%s" % a_name)
1406 if a_type in classes_type:
1407 classes.write("__o")
1408 classes.write(")\n")
1410 if r_type != "void":
1411 if r_type in classes_type:
1413 # Raise an exception
1415 if name in functions_noexcept:
1416 classes.write(" if ret is None:\n"
1417 " return None\n")
1418 else:
1419 classes.write(
1420 " if ret is None:\n"
1421 " raise libvirtError('%s() failed')\n" %
1422 (name))
1424 tinfo = classes_type[r_type]
1425 classes.write(" return ")
1426 classes.write(tinfo[1] % {"o": "ret"})
1427 classes.write("\n")
1429 # For functions returning an integral type there are
1430 # several things that we can do, depending on the
1431 # contents of functions_int_*:
1432 elif is_integral_type(r_type):
1433 if name not in functions_noexcept:
1434 test = functions_int_exception_test.get(name, functions_int_default_test) % ("ret",)
1435 classes.write(
1436 " if %s:\n"
1437 " raise libvirtError('%s() failed')\n" %
1438 (test, name))
1439 classes.write(" return ret\n")
1441 elif is_python_noninteger_type(r_type):
1442 if name not in functions_noexcept:
1443 classes.write(
1444 " if ret is None:\n"
1445 " raise libvirtError('%s() failed')\n" %
1446 (name,))
1447 classes.write(" return ret\n")
1449 else:
1450 classes.write(" return ret\n")
1452 classes.write("\n")
1454 modclasses = []
1455 if module == "libvirt":
1456 modclasses = classes_list
1457 for classname in modclasses:
1458 PARENTS = {
1459 "virConnect": "self._conn",
1460 "virDomain": "self._dom",
1461 "virNetwork": "self._net",
1462 classname: "self",
1465 if classname == "None":
1466 pass
1467 else:
1468 classes.write("class %s(object):\n" % (classname))
1469 if classname == "virStorageVol":
1470 classes.write(" # The size (in bytes) of buffer used in sendAll(),\n")
1471 classes.write(" # recvAll(), sparseSendAll() and sparseRecvAll()\n")
1472 classes.write(" # methods. This corresponds to the size of payload\n")
1473 classes.write(" # of a stream packet.\n")
1474 classes.write(" streamBufSize = 262120\n\n")
1475 if classname in ["virDomain", "virNetwork", "virInterface", "virStoragePool",
1476 "virStorageVol", "virNodeDevice", "virSecret", "virStream",
1477 "virNWFilter", "virNWFilterBinding"]:
1478 classes.write(" def __init__(self, conn, _obj=None):\n")
1479 classes.write(" self._conn = conn\n")
1480 elif classname in ["virDomainCheckpoint", "virDomainSnapshot"]:
1481 classes.write(" def __init__(self, dom, _obj=None):\n")
1482 classes.write(" self._dom = dom\n")
1483 classes.write(" self._conn = dom.connect()\n")
1484 elif classname in ["virNetworkPort"]:
1485 classes.write(" def __init__(self, net, _obj=None) -> None:\n")
1486 classes.write(" self._net = net\n")
1487 classes.write(" self._conn = net.connect()\n")
1488 else:
1489 classes.write(" def __init__(self, _obj=None):\n")
1491 classes.write(" if type(_obj).__name__ not in [\"PyCapsule\", \"PyCObject\"]:\n")
1492 classes.write(" raise Exception(\"Expected a wrapped C Object but got %s\" % type(_obj))\n")
1493 classes.write(" self._o = _obj\n\n")
1494 destruct = None
1495 if classname in classes_destructors:
1496 classes.write(" def __del__(self):\n")
1497 classes.write(" if self._o is not None:\n")
1498 classes.write(" %s.%s(self._o)\n" %
1499 (pymod, classes_destructors[classname]))
1500 classes.write(" self._o = None\n\n")
1501 destruct = classes_destructors[classname]
1503 if classname not in class_skip_connect_impl:
1504 # Build python safe 'connect' method
1505 classes.write(" def connect(self):\n")
1506 classes.write(" return self._conn\n\n")
1508 if classname in class_domain_impl:
1509 classes.write(" def domain(self):\n")
1510 classes.write(" return self._dom\n\n")
1512 if classname in class_network_impl:
1513 classes.write(" def network(self):\n")
1514 classes.write(" return self._net\n\n")
1516 classes.write(" def c_pointer(self):\n")
1517 classes.write(" \"\"\"Get C pointer to underlying object\"\"\"\n")
1518 classes.write(" return %s.%s_pointer(self._o)\n\n" %
1519 (pymod, classname))
1521 flist = function_classes[classname]
1522 oldfile = ""
1523 for (index, func, name, ret, args, file, mod) in sorted(flist, key=functionSortKey):
1525 # Do not provide as method the destructors for the class
1526 # to avoid double free
1528 if name == destruct:
1529 continue
1530 if file != oldfile:
1531 if file == "python_accessor":
1532 classes.write(" # accessors for %s\n" % (classname))
1533 else:
1534 classes.write(" #\n")
1535 classes.write(" # %s functions from module %s\n" % (
1536 classname, file))
1537 classes.write(" #\n\n")
1538 oldfile = file
1539 classes.write(" def %s(self" % func)
1540 for n, (a_name, a_type, a_info) in enumerate(args):
1541 if n != index:
1542 classes.write(", %s" % a_name)
1543 if a_name == "flags" or is_optional_arg(a_info):
1544 if is_integral_type(a_type):
1545 classes.write("=0")
1546 else:
1547 classes.write("=None")
1548 classes.write("):\n")
1549 writeDoc(module, name, args, ' ', classes)
1550 for n, (a_name, a_type, a_info) in enumerate(args):
1551 if a_type in classes_type:
1552 if n != index:
1553 classes.write(" if %s is None:\n"
1554 " %s__o = None\n" %
1555 (a_name, a_name))
1556 classes.write(" else:\n"
1557 " %s__o = %s%s\n" %
1558 (a_name, a_name, classes_type[a_type][0]))
1559 r_type, r_info, r_field = ret
1560 if r_type != "void":
1561 classes.write(" ret = ")
1562 else:
1563 classes.write(" ")
1564 classes.write("%s.%s(" % (pymod, name))
1565 for n, (a_name, a_type, a_info) in enumerate(args):
1566 if n != 0:
1567 classes.write(", ")
1568 if n != index:
1569 classes.write("%s" % a_name)
1570 if a_type in classes_type:
1571 classes.write("__o")
1572 else:
1573 classes.write("self")
1574 if a_type in classes_type:
1575 classes.write(classes_type[a_type][0])
1576 classes.write(")\n")
1578 if name == "virConnectClose":
1579 classes.write(" self._o = None\n")
1581 # For functions returning object types:
1582 if r_type != "void":
1583 if r_type in classes_type:
1585 # Raise an exception
1587 if name in functions_noexcept:
1588 classes.write(
1589 " if ret is None:\n"
1590 " return None\n")
1591 else:
1592 classes.write(
1593 " if ret is None:\n"
1594 " raise libvirtError('%s() failed')\n" %
1595 (name,))
1598 # generate the returned class wrapper for the object
1600 tinfo = classes_type[r_type]
1601 classes.write(" __tmp = ")
1602 classes.write(tinfo[1] % {"o": "ret", "p": PARENTS[tinfo[3]]})
1603 classes.write("\n")
1606 # return the class
1608 classes.write(" return __tmp\n")
1610 # For functions returning an integral type there
1611 # are several things that we can do, depending on
1612 # the contents of functions_int_*:
1613 elif is_integral_type(r_type):
1614 if name not in functions_noexcept:
1615 test = functions_int_exception_test.get(name, functions_int_default_test) % ("ret",)
1616 classes.write(
1617 " if %s:\n"
1618 " raise libvirtError('%s() failed')\n" %
1619 (test, name))
1621 classes.write(" return ret\n")
1623 elif is_python_noninteger_type(r_type):
1624 if name not in functions_noexcept:
1625 classes.write(
1626 " if ret is None:\n"
1627 " raise libvirtError('%s() failed')\n" %
1628 (name,))
1630 classes.write(" return ret\n")
1631 else:
1632 classes.write(" return ret\n")
1634 classes.write("\n")
1635 # Append "<classname>.py" to class def, iff it exists
1636 class_override = "%s-override-%s.py" % (module, classname)
1637 extra = openSourceFile(class_override, "r", True)
1638 if extra:
1639 classes.write(" #\n")
1640 classes.write(" # %s methods from %s.py (hand coded)\n" % (classname, classname))
1641 classes.write(" #\n")
1642 cached = None
1644 # Since we compile with older libvirt, we don't want to pull
1645 # in manually written python methods which call C methods
1646 # that don't exist. This code attempts to detect which
1647 # methods to skip by looking at the libvirtmod.XXXX calls
1649 def shouldSkip(lines: List[str]) -> bool:
1650 for line in lines:
1651 offset = line.find(pymod + ".")
1652 if offset != -1:
1653 func = line[offset + 11:]
1654 offset = func.find("(")
1655 func = func[0:offset]
1656 if not skip_c_impl(func) and func != "virConnectListDomains":
1657 return True
1658 return False
1660 for line in extra.readlines():
1661 offset = line.find(" def ")
1662 if offset != -1:
1663 name = line[offset + 5:]
1664 offset = name.find("(")
1665 name = name[0:offset]
1666 if cached:
1667 if not shouldSkip(cached):
1668 classes.writelines(cached)
1669 if name == "__del__":
1670 cached = None
1671 classes.write(line)
1672 else:
1673 cached = [line]
1674 else:
1675 if cached:
1676 cached.append(line)
1677 else:
1678 classes.write(line)
1679 if cached is not None and not shouldSkip(cached):
1680 classes.writelines(cached)
1681 classes.write("\n")
1682 extra.close()
1684 direct_functions = {}
1685 if module != "libvirt":
1686 direct_functions = functions
1688 classes.write("#\n# Functions from module %s\n#\n\n" % module)
1691 # Generate functions directly, no classes
1693 for name, (desc, ret, args, file, mod, cond) in sorted(direct_functions.items()):
1694 if skip_py_impl(name):
1695 continue
1696 func = nameFixup(name, 'None', '', '')
1697 classes.write("def %s(" % func)
1698 for n, (a_name, a_type, a_info) in enumerate(args):
1699 if n != 0:
1700 classes.write(", ")
1701 classes.write("%s" % a_name)
1702 classes.write("):\n")
1703 writeDoc(module, name, args, ' ', classes)
1705 r_type, r_info, r_field = ret
1706 if r_type != "void":
1707 classes.write(" ret = ")
1708 else:
1709 classes.write(" ")
1710 classes.write("%s.%s(" % (pymod, name))
1712 conn = None
1714 for n, (a_name, a_type, a_info) in enumerate(args):
1715 if a_type == "virConnectPtr":
1716 conn = a_name
1718 if n != 0:
1719 classes.write(", ")
1720 if a_type in ["virDomainPtr", "virConnectPtr"]:
1721 # FIXME: This might have problem if the function
1722 # has multiple args which are objects.
1723 classes.write("%s.%s" % (a_name, "_o"))
1724 else:
1725 classes.write("%s" % a_name)
1726 classes.write(")\n")
1728 if r_type != "void":
1729 classes.write(" if ret is None:\n"
1730 " raise libvirt.libvirtError('%s() failed')\n" % (name,))
1731 if r_type == "virDomainPtr":
1732 classes.write(" __tmp = libvirt.virDomain(%s, _obj=ret)\n" % (conn,))
1733 classes.write(" return __tmp\n")
1734 else:
1735 classes.write(" return ret\n")
1737 classes.write("\n")
1740 # Generate enum constants
1742 def enumsSortKey(data: Tuple[str, EnumValue]) -> Tuple[Union[int, float], str]:
1743 try:
1744 value = int(data[1]) # type: Union[int, float]
1745 except ValueError:
1746 value = float('inf')
1747 return value, data[0]
1749 # Resolve only one level of reference
1750 def resolveEnum(enum: EnumType, data: EnumType) -> EnumType:
1751 for name, val in enum.items():
1752 try:
1753 int(val)
1754 except ValueError:
1755 enum[name] = data[val] # type: ignore
1756 return enum
1758 enumvals = list(enums.items())
1759 # convert list of dicts to one dict
1760 enumData = {} # type: EnumType
1761 for type, enum in enumvals:
1762 enumData.update(enum)
1764 for type, enum in sorted(enumvals):
1765 classes.write("# %s\n" % type)
1766 items = sorted(resolveEnum(enum, enumData).items(), key=enumsSortKey)
1767 if items[-1][0].endswith('_LAST'):
1768 del items[-1]
1769 for name, value in items:
1770 classes.write("%s = %s\n" % (name, value))
1771 classes.write("\n")
1773 if params:
1774 classes.write("# typed parameter names\n")
1775 for name, value in params:
1776 classes.write("%s = \"%s\"\n" % (name, value))
1778 classes.close()
1780 if sys.argv[1] not in ["libvirt", "libvirt-lxc", "libvirt-qemu"]:
1781 print("ERROR: unknown module %s" % sys.argv[1])
1782 sys.exit(1)
1784 if len(sys.argv) == 6:
1785 buildDir = sys.argv[5]
1786 if len(sys.argv) >= 5:
1787 sourceDir = sys.argv[4]
1789 load_apis(sys.argv[1], sys.argv[2])
1791 if validate_functions() < 0:
1792 sys.exit(1)
1794 quiet = False
1795 if not os.path.exists("build"):
1796 os.mkdir("build")
1798 output = None
1799 if len(sys.argv) >= 4:
1800 output = sys.argv[3]
1801 if output == "c" or output == "c+py" or output is None:
1802 emit_c_code(sys.argv[1])
1804 if output == "py" or output == "c+py" or output is None:
1805 emit_py_code(sys.argv[1])
1807 sys.exit(0)