3 # generate python wrappers from the XML API description
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)... ]
26 #######################################################################
28 # That part if purely the API acquisition phase from the
29 # libvirt API description
31 #######################################################################
41 "libvirt-domain-checkpoint",
42 "libvirt-domain-snapshot",
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
):
58 return open(path
, mode
)
60 def parse(data
: IO
[str]) -> None:
62 with
closing(xml
.sax
.make_parser()) as parser
:
63 parser
.setContentHandler(target
)
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:
74 print("data %s" % text
)
75 self
._data
.append(text
)
77 def startElement(self
, tag
: str, attrs
: Dict
[str, str]) -> None:
79 print("start %s, %s" % (tag
, attrs
))
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', '')
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':
103 self
.function_return_type
= attrs
.get('type', '')
104 self
.function_return_info
= attrs
.get('info', '')
105 self
.function_return_field
= attrs
.get('field', '')
107 # enums come from header files, hence virterror.h
108 files
= libvirt_headers
+ ["virerror",
112 if attrs
['file'] in files
:
113 enum(attrs
['type'], attrs
['name'], attrs
['value'])
115 if "string" in attrs
:
116 params
.append((attrs
['name'], attrs
['string']))
118 def endElement(self
, tag
: str) -> None:
120 print("end %s" % tag
)
121 if tag
== 'function':
122 # functions come from source files, hence 'virerror.c'
124 assert self
.function_return
126 modules
= libvirt_headers
+ ["event",
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
,
140 self
.in_function
= False
143 self
.function_args
.append((self
.function_arg_name
,
144 self
.function_arg_type
,
145 self
.function_arg_info
))
146 elif tag
== 'return':
148 self
.function_return
= (self
.function_return_type
,
149 self
.function_return_info
,
150 self
.function_return_field
)
152 str = ''.join(self
._data
)
154 self
.function_descr
= str
156 str = ''.join(self
._data
)
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
:
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':
175 elif value
== 'VIR_TYPED_PARAM_UINT':
177 elif value
== 'VIR_TYPED_PARAM_LLONG':
179 elif value
== 'VIR_TYPED_PARAM_ULLONG':
181 elif value
== 'VIR_TYPED_PARAM_DOUBLE':
183 elif value
== 'VIR_TYPED_PARAM_BOOLEAN':
185 elif value
== 'VIR_DOMAIN_AFFECT_CURRENT':
187 elif value
== 'VIR_DOMAIN_AFFECT_LIVE':
189 elif value
== 'VIR_DOMAIN_AFFECT_CONFIG':
191 elif value
== 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK':
193 elif value
== 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_DEFAULT':
195 elif value
== 'VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_NOWAIT':
198 if onlyOverrides
and name
not in enums
[type]:
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 #######################################################################
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
230 #######################################################################
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()).
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',
334 'virDomainGetControlInfo',
335 'virDomainGetBlockInfo',
336 'virDomainGetJobInfo',
337 'virDomainGetJobStats',
339 'virNodeGetSecurityModel',
340 'virDomainGetSecurityLabel',
341 'virDomainGetSecurityLabelList',
343 'virDomainGetUUIDString',
344 'virDomainLookupByUUID',
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',
370 'virDomainPinVcpuFlags',
371 'virDomainGetVcpuPinInfo',
372 'virDomainGetEmulatorPinInfo',
373 'virDomainPinEmulator',
374 'virDomainGetIOThreadInfo',
375 'virDomainPinIOThread',
376 'virDomainSetIOThreadParams',
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',
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',
419 'virDomainMigrateToURI3',
420 'virConnectGetCPUModelNames',
421 'virNodeGetFreePages',
422 'virNetworkGetDHCPLeases',
423 'virDomainBlockCopy',
425 'virDomainGetFSInfo',
426 'virDomainInterfaceAddresses',
427 'virDomainGetPerfEvents',
428 'virDomainSetPerfEvents',
429 'virDomainGetGuestVcpus',
430 'virConnectBaselineHypervisorCPU',
431 'virDomainGetLaunchSecurityInfo',
432 'virDomainSetLaunchSecurityState',
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
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.
526 "virNWFilterBindingRef",
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",
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
:
600 if name
in skip_impl
:
605 for a_name
, a_type
, a_info
in args
:
606 # This should be correct
607 if a_type
[0:6] == "const ":
610 if a_type
in skipped_types
:
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
:
619 if r_type
!= 'void' and r_type
not in py_types
:
620 unknown
.append(r_type
)
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
)
632 funcs_failed
.append(name
)
633 for thetype
in unknown
:
634 unknown_types
[thetype
].append(name
)
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
)
650 def skip_both_impl(name
: str) -> bool:
651 if name
in skip_function
:
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 ":
661 if a_type
in skipped_types
:
664 r_type
, r_info
, r_field
= ret
665 if r_type
in skipped_types
:
671 def skip_c_impl(name
: str) -> bool:
672 if skip_both_impl(name
):
675 if name
in skip_impl
:
681 def skip_py_impl(name
: str) -> bool:
682 if skip_both_impl(name
):
685 if name
in function_skip_python_impl
:
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
):
707 for a_name
, a_type
, a_info
in args
:
708 # This should be correct
709 if a_type
[0:6] == "const ":
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
]
717 format_args
+= ", &pyobj_%s" % (a_name
)
718 c_args
+= " PyObject *pyobj_%s;\n" % (a_name
)
720 " %s = (%s) Py%s_Get(pyobj_%s);\n" % (
721 a_name
, a_type
, t
, a_name
)
723 format_args
+= ", &%s" % (a_name
)
725 format_args
+= ", &py_buffsize%d" % num_bufs
726 c_args
+= " int py_buffsize%d;\n" % num_bufs
730 c_call
+= "%s" % (a_name
)
732 raise Exception("Unexpected type %s in function %s" % (a_type
, name
))
734 format
+= ":%s" % (name
)
736 r_type
, r_info
, r_field
= ret
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])
745 c_call
= "\n %s->%s = %s;\n" % (args
[0][0], args
[1][0],
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
)
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
)
759 ret_convert
+= " free(c_retval);\n"
760 ret_convert
+= " return py_retval;\n"
762 raise Exception("Unexpected type %s in function %s" % (r_type
, name
))
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
))
775 # Those have been manually generated
777 include
.write("#endif\n")
778 export
.write("#endif\n")
779 output
.write("#endif\n")
781 if file == "python_accessor" and r_type
!= "void" and not r_field
:
782 # Those have been manually generated
784 include
.write("#endif\n")
785 export
.write("#endif\n")
786 output
.write("#endif\n")
789 output
.write("PyObject *\n")
790 output
.write("%s_%s(PyObject *self ATTRIBUTE_UNUSED," % (package
, name
))
791 output
.write(" PyObject *args")
793 output
.write(" ATTRIBUTE_UNUSED")
794 output
.write(") {\n")
796 output
.write(" PyObject *py_retval;\n")
798 output
.write(c_return
)
802 output
.write("\n if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" %
803 (format
, format_args
))
804 output
.write(" return NULL;\n")
806 output
.write(c_convert
+ "\n")
808 output
.write(" LIBVIRT_BEGIN_ALLOW_THREADS;")
810 output
.write(" LIBVIRT_END_ALLOW_THREADS;\n")
811 output
.write(ret_convert
)
812 output
.write("}\n\n")
814 include
.write("#endif /* %s */\n" % cond
)
815 export
.write("#endif /* %s */\n" % cond
)
816 output
.write("#endif /* %s */\n" % cond
)
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
)
825 output
.write(" %sPtr ptr;\n" % classname
)
826 output
.write(" PyObject *pyptr;\n")
827 output
.write(" PyObject *pylong;\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")
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):
847 onlyOverrides
= False
848 with
open(api_xml
) as stream
:
850 except IOError as msg
:
851 print(api_xml
, ":", msg
)
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")
863 with
openSourceFile(override_api_xml
) as stream
:
865 except IOError as msg
:
866 print(override_api_xml
, ":", msg
)
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('-', '_')
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
):
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
))
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)
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
= {
988 class_domain_impl
= {
989 "virDomainCheckpoint",
993 class_network_impl
= {
997 functions_noexcept
= {
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
= {
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"
1042 if name
[0:l
] == listname
:
1044 func
= func
[0:1].lower() + func
[1:]
1045 elif name
[0:16] == "virNetworkDefine":
1047 func
= func
[0:1].lower() + func
[1:]
1048 elif name
[0:19] == "virNetworkCreateXML":
1050 func
= func
[0:1].lower() + func
[1:]
1051 elif name
[0:16] == "virNetworkLookup":
1053 func
= func
[0:1].lower() + func
[1:]
1054 elif name
[0:23] == "virNetworkPortCreateXML":
1056 func
= func
[0:1].lower() + func
[1:]
1057 elif name
[0:20] == "virNetworkPortLookup":
1059 func
= func
[0:1].lower() + func
[1:]
1060 elif name
[0:18] == "virInterfaceDefine":
1062 func
= func
[0:1].lower() + func
[1:]
1063 elif name
[0:21] == "virInterfaceCreateXML":
1065 func
= func
[0:1].lower() + func
[1:]
1066 elif name
[0:18] == "virInterfaceLookup":
1068 func
= func
[0:1].lower() + func
[1:]
1069 elif name
[0:15] == "virSecretDefine":
1071 func
= func
[0:1].lower() + func
[1:]
1072 elif name
[0:15] == "virSecretLookup":
1074 func
= func
[0:1].lower() + func
[1:]
1075 elif name
[0:27] == "virNWFilterBindingCreateXML":
1077 func
= func
[0:3].lower() + func
[3:]
1078 elif name
[0:24] == "virNWFilterBindingLookup":
1080 func
= func
[0:3].lower() + func
[3:]
1081 elif name
[0:24] == "virNWFilterBindingDefine":
1083 func
= func
[0:3].lower() + func
[3:]
1084 elif name
[0:24] == "virNWFilterBindingLookup":
1086 func
= func
[0:3].lower() + func
[3:]
1087 elif name
[0:17] == "virNWFilterDefine":
1089 func
= func
[0:3].lower() + func
[3:]
1090 elif name
[0:17] == "virNWFilterLookup":
1092 func
= func
[0:3].lower() + func
[3:]
1093 elif name
[0:20] == "virStoragePoolDefine":
1095 func
= func
[0:1].lower() + func
[1:]
1096 elif name
[0:23] == "virStoragePoolCreateXML":
1098 func
= func
[0:1].lower() + func
[1:]
1099 elif name
[0:20] == "virStoragePoolLookup":
1101 func
= func
[0:1].lower() + func
[1:]
1102 elif name
[0:19] == "virStorageVolDefine":
1104 func
= func
[0:1].lower() + func
[1:]
1105 elif name
[0:19] == "virStorageVolLookup":
1107 func
= func
[0:1].lower() + func
[1:]
1108 elif name
[0:20] == "virDomainGetCPUStats":
1110 func
= func
[0:1].lower() + func
[1:]
1111 elif name
[0:24] == "virDomainGetIOThreadInfo":
1113 func
= func
[0:2].lower() + func
[2:]
1114 elif name
[0:18] == "virDomainGetFSInfo":
1116 func
= func
[0:2].lower() + func
[2:]
1117 elif name
[0:12] == "virDomainGet":
1119 func
= func
[0:1].lower() + func
[1:]
1120 elif name
[0:31] == "virDomainCheckpointLookupByName":
1122 func
= func
[0:1].lower() + func
[1:]
1123 elif name
[0:28] == "virDomainCheckpointCreateXML":
1125 func
= func
[0:1].lower() + func
[1:]
1126 elif name
[0:19] == "virDomainCheckpoint":
1128 func
= func
[0:1].lower() + func
[1:]
1129 elif name
[0:29] == "virDomainSnapshotLookupByName":
1131 func
= func
[0:1].lower() + func
[1:]
1132 elif name
[0:26] == "virDomainSnapshotListNames":
1134 func
= func
[0:1].lower() + func
[1:]
1135 elif name
[0:28] == "virDomainSnapshotNumChildren":
1137 func
= func
[0:1].lower() + func
[1:]
1138 elif name
[0:20] == "virDomainSnapshotNum":
1140 func
= func
[0:1].lower() + func
[1:]
1141 elif name
[0:26] == "virDomainSnapshotCreateXML":
1143 func
= func
[0:1].lower() + func
[1:]
1144 elif name
[0:24] == "virDomainSnapshotCurrent":
1146 func
= func
[0:1].lower() + func
[1:]
1147 elif name
[0:17] == "virDomainSnapshot":
1149 func
= func
[0:1].lower() + func
[1:]
1150 elif name
[0:9] == "virDomain":
1152 func
= func
[0:1].lower() + func
[1:]
1153 elif name
[0:17] == "virNetworkPortGet":
1155 func
= func
[0:1].lower() + func
[1:]
1156 elif name
[0:13] == "virNetworkGet":
1158 func
= func
[0:1].lower() + func
[1:]
1159 func
= func
.replace("dHCP", "DHCP")
1160 elif name
[0:14] == "virNetworkPort":
1162 func
= func
[0:1].lower() + func
[1:]
1163 elif name
[0:10] == "virNetwork":
1165 func
= func
[0:1].lower() + func
[1:]
1166 elif name
[0:15] == "virInterfaceGet":
1168 func
= func
[0:1].lower() + func
[1:]
1169 elif name
[0:12] == "virInterface":
1171 func
= func
[0:1].lower() + func
[1:]
1172 elif name
[0:12] == 'virSecretGet':
1174 func
= func
[0:1].lower() + func
[1:]
1175 elif name
[0:9] == 'virSecret':
1177 func
= func
[0:1].lower() + func
[1:]
1178 elif name
[0:21] == 'virNWFilterBindingGet':
1180 func
= func
[0:1].lower() + func
[1:]
1181 elif name
[0:18] == 'virNWFilterBinding':
1183 func
= func
[0:1].lower() + func
[1:]
1184 elif name
[0:14] == 'virNWFilterGet':
1186 func
= func
[0:1].lower() + func
[1:]
1187 elif name
[0:11] == 'virNWFilter':
1189 func
= func
[0:1].lower() + func
[1:]
1190 elif name
[0:12] == 'virStreamNew':
1192 elif name
[0:9] == 'virStream':
1194 func
= func
[0:1].lower() + func
[1:]
1195 elif name
[0:17] == "virStoragePoolGet":
1197 func
= func
[0:1].lower() + func
[1:]
1198 elif name
[0:14] == "virStoragePool":
1200 func
= func
[0:1].lower() + func
[1:]
1201 elif name
[0:16] == "virStorageVolGet":
1203 func
= func
[0:1].lower() + func
[1:]
1204 elif name
[0:13] == "virStorageVol":
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":
1219 func
= func
[0:1].lower() + func
[1:]
1220 elif name
[0:10] == "virConnect":
1222 func
= func
[0:1].lower() + func
[1:]
1223 elif name
[0:3] == "xml":
1225 func
= func
[0:1].lower() + func
[1:]
1232 if func
== "uUIDString":
1234 if func
== "oSType":
1236 if func
== "xMLDesc":
1238 if func
== "mACString":
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]:
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"
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
:
1289 ctypes_processed
.add(type)
1290 for type, tinfo
in classes_type
.items():
1291 if type in ctypes_processed
:
1293 if tinfo
[2] not in classes_processed
:
1294 classes_list
.append(tinfo
[2])
1295 classes_processed
.add(tinfo
[2])
1298 ctypes_processed
.add(type)
1300 for name
, (desc
, ret
, args
, file, mod
, cond
) in functions
.items():
1301 if skip_py_impl(name
):
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
)
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
)
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")
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")
1367 if "None" in function_classes
:
1368 flist
= function_classes
["None"]
1370 for (index
, func
, name
, ret
, args
, file, mod
) in sorted(flist
, key
=functionSortKey
):
1372 classes
.write("#\n# Functions from module %s\n#\n\n" % file)
1374 classes
.write("def %s(" % func
)
1375 for n
, (a_name
, a_type
, a_info
) in enumerate(args
):
1378 classes
.write("%s" % a_name
)
1379 if a_name
== "flags" or is_optional_arg(a_info
):
1380 if is_integral_type(a_type
):
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"
1392 classes
.write(" else:\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 = ")
1401 classes
.write("%s.%s(" % (pymod
, name
))
1402 for n
, (a_name
, a_type
, a_info
) in enumerate(args
):
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"
1420 " if ret is None:\n"
1421 " raise libvirtError('%s() failed')\n" %
1424 tinfo
= classes_type
[r_type
]
1425 classes
.write(" return ")
1426 classes
.write(tinfo
[1] % {"o": "ret"})
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",)
1437 " raise libvirtError('%s() failed')\n" %
1439 classes
.write(" return ret\n")
1441 elif is_python_noninteger_type(r_type
):
1442 if name
not in functions_noexcept
:
1444 " if ret is None:\n"
1445 " raise libvirtError('%s() failed')\n" %
1447 classes
.write(" return ret\n")
1450 classes
.write(" return ret\n")
1455 if module
== "libvirt":
1456 modclasses
= classes_list
1457 for classname
in modclasses
:
1459 "virConnect": "self._conn",
1460 "virDomain": "self._dom",
1461 "virNetwork": "self._net",
1465 if classname
== "None":
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")
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")
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" %
1521 flist
= function_classes
[classname
]
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
:
1531 if file == "python_accessor":
1532 classes
.write(" # accessors for %s\n" % (classname
))
1534 classes
.write(" #\n")
1535 classes
.write(" # %s functions from module %s\n" % (
1537 classes
.write(" #\n\n")
1539 classes
.write(" def %s(self" % func
)
1540 for n
, (a_name
, a_type
, a_info
) in enumerate(args
):
1542 classes
.write(", %s" % a_name
)
1543 if a_name
== "flags" or is_optional_arg(a_info
):
1544 if is_integral_type(a_type
):
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
:
1553 classes
.write(" if %s is None:\n"
1556 classes
.write(" else:\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 = ")
1564 classes
.write("%s.%s(" % (pymod
, name
))
1565 for n
, (a_name
, a_type
, a_info
) in enumerate(args
):
1569 classes
.write("%s" % a_name
)
1570 if a_type
in classes_type
:
1571 classes
.write("__o")
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
:
1589 " if ret is None:\n"
1593 " if ret is None:\n"
1594 " raise libvirtError('%s() failed')\n" %
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]]})
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",)
1618 " raise libvirtError('%s() failed')\n" %
1621 classes
.write(" return ret\n")
1623 elif is_python_noninteger_type(r_type
):
1624 if name
not in functions_noexcept
:
1626 " if ret is None:\n"
1627 " raise libvirtError('%s() failed')\n" %
1630 classes
.write(" return ret\n")
1632 classes
.write(" return ret\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)
1639 classes
.write(" #\n")
1640 classes
.write(" # %s methods from %s.py (hand coded)\n" % (classname
, classname
))
1641 classes
.write(" #\n")
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:
1651 offset
= line
.find(pymod
+ ".")
1653 func
= line
[offset
+ 11:]
1654 offset
= func
.find("(")
1655 func
= func
[0:offset
]
1656 if not skip_c_impl(func
) and func
!= "virConnectListDomains":
1660 for line
in extra
.readlines():
1661 offset
= line
.find(" def ")
1663 name
= line
[offset
+ 5:]
1664 offset
= name
.find("(")
1665 name
= name
[0:offset
]
1667 if not shouldSkip(cached
):
1668 classes
.writelines(cached
)
1669 if name
== "__del__":
1679 if cached
is not None and not shouldSkip(cached
):
1680 classes
.writelines(cached
)
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
):
1696 func
= nameFixup(name
, 'None', '', '')
1697 classes
.write("def %s(" % func
)
1698 for n
, (a_name
, a_type
, a_info
) in enumerate(args
):
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 = ")
1710 classes
.write("%s.%s(" % (pymod
, name
))
1714 for n
, (a_name
, a_type
, a_info
) in enumerate(args
):
1715 if a_type
== "virConnectPtr":
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"))
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")
1735 classes
.write(" return ret\n")
1740 # Generate enum constants
1742 def enumsSortKey(data
: Tuple
[str, EnumValue
]) -> Tuple
[Union
[int, float], str]:
1744 value
= int(data
[1]) # type: Union[int, float]
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():
1755 enum
[name
] = data
[val
] # type: ignore
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'):
1769 for name
, value
in items
:
1770 classes
.write("%s = %s\n" % (name
, value
))
1774 classes
.write("# typed parameter names\n")
1775 for name
, value
in params
:
1776 classes
.write("%s = \"%s\"\n" % (name
, value
))
1780 if sys
.argv
[1] not in ["libvirt", "libvirt-lxc", "libvirt-qemu"]:
1781 print("ERROR: unknown module %s" % sys
.argv
[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:
1795 if not os
.path
.exists("build"):
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])