From: "Max R. Carrara" <m.carrara@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v1 pve-esxi-import-tools 1/5] listvms: respect new type hints of pyVmomi package
Date: Fri, 18 Jul 2025 18:19:01 +0200 [thread overview]
Message-ID: <20250718161905.461482-2-m.carrara@proxmox.com> (raw)
In-Reply-To: <20250718161905.461482-1-m.carrara@proxmox.com>
This makes mypy on trixie happy again.
Make the type hints explicit; even though this is a little more
verbose, it should make any typing-related changes more visible in the
future. Also return (hopefully) sane defaults wherever possible.
Note that Python doesn't have something like "null-aware member
access" like JS does, so there isn't really any prettier version of
doing this.
(Besides, I have *never* seen as many `Optional`s in any Python
codebase as in the pyVmomi package's type stubs, let alone their
"on-demand loading" of types.)
Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
---
listvms.py | 95 ++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 81 insertions(+), 14 deletions(-)
diff --git a/listvms.py b/listvms.py
index 44f207c..221d562 100755
--- a/listvms.py
+++ b/listvms.py
@@ -162,14 +162,29 @@ def get_datacenter_of_vm(vm: vim.VirtualMachine) -> vim.Datacenter | None:
def list_vms(service_instance: vim.ServiceInstance) -> list[vim.VirtualMachine]:
"""List all VMs on the ESXi/vCenter server."""
- content = service_instance.content
- vm_view: Any = content.viewManager.CreateContainerView(
+
+ content: vim.ServiceInstanceContent | None = service_instance.content
+
+ if content is None:
+ return []
+
+ view_manager: vim.view.ViewManager | None = content.viewManager
+
+ if view_manager is None:
+ return []
+
+ vm_view = view_manager.CreateContainerView(
content.rootFolder,
[vim.VirtualMachine],
True,
)
+
+ if vm_view is None:
+ return []
+
vms = vm_view.view
vm_view.Destroy()
+
return vms
@@ -180,23 +195,42 @@ def parse_file_path(path) -> tuple[str, str]:
return (datastore_name, relative_path)
-def get_vm_vmx_info(vm: vim.VirtualMachine) -> VmVmxInfo:
+def get_vm_vmx_info(vm: vim.VirtualMachine) -> VmVmxInfo | None:
"""Extract VMX file path and checksum from a VM object."""
- datastore_name, relative_vmx_path = parse_file_path(
- vm.config.files.vmPathName
+
+ config: vim.vm.ConfigInfo | None = vm.config
+
+ if config is None:
+ return None
+
+ files: vim.vm.FileInfo | None = config.files
+
+ if files is None:
+ return None
+
+ vm_path_name: str | None = files.vmPathName
+
+ if vm_path_name is None:
+ return None
+
+ datastore_name, relative_vmx_path = parse_file_path(vm_path_name)
+ checksum = (
+ config.vmxConfigChecksum.hex() if config.vmxConfigChecksum else "N/A"
)
return VmVmxInfo(
datastore=datastore_name,
path=relative_vmx_path,
- checksum=vm.config.vmxConfigChecksum.hex()
- if vm.config.vmxConfigChecksum
- else "N/A",
+ checksum=checksum,
)
def get_vm_disk_info(vm: vim.VirtualMachine) -> list[VmDiskInfo]:
- disks = []
+ disks: list[VmDiskInfo] = []
+
+ if vm.config is None:
+ return disks
+
for device in vm.config.hardware.device:
if isinstance(device, vim.vm.device.VirtualDisk):
try:
@@ -217,12 +251,27 @@ def get_all_datacenters(
service_instance: vim.ServiceInstance,
) -> list[vim.Datacenter]:
"""Retrieve all datacenters from the ESXi/vCenter server."""
- content = service_instance.content
- dc_view: Any = content.viewManager.CreateContainerView(
+
+ content: vim.ServiceInstanceContent | None = service_instance.content
+
+ if content is None:
+ return []
+
+ view_manager: vim.view.ViewManager | None = content.viewManager
+
+ if view_manager is None:
+ return []
+
+ dc_view = view_manager.CreateContainerView(
content.rootFolder, [vim.Datacenter], True
)
+
+ if dc_view is None:
+ return []
+
datacenters = dc_view.view
dc_view.Destroy()
+
return datacenters
@@ -242,13 +291,28 @@ def fetch_and_update_vm_data(vm: vim.VirtualMachine, data: dict[Any, Any]):
vms = data[datacenter.name].setdefault("vms", {})
datastores = data[datacenter.name].setdefault("datastores", {})
+ config: vim.vm.ConfigInfo | None = vm.config
+
+ if config is None:
+ return
+
+ vm_vmx_info: VmVmxInfo | None = get_vm_vmx_info(vm)
+
+ if vm_vmx_info is None:
+ return
+
+ runtime: vim.vm.RuntimeInfo | None = vm.runtime
+
+ if runtime is None:
+ return
+
vms[vm.name] = VmInfo(
- config=get_vm_vmx_info(vm),
+ config=vm_vmx_info,
disks=get_vm_disk_info(vm),
- power=str(vm.runtime.powerState),
+ power=str(runtime.powerState),
)
- datastores.update({ds.name: ds.url for ds in vm.config.datastoreUrl})
+ datastores.update({ds.name: ds.url for ds in config.datastoreUrl})
def is_vcls_agent_vm(vm: vim.VirtualMachine) -> bool:
@@ -261,6 +325,9 @@ def is_vcls_agent_vm(vm: vim.VirtualMachine) -> bool:
for cfg in vm.config.extraConfig)
def is_diskless_vm(vm: vim.VirtualMachine) -> bool:
+ if vm.config is None or vm.config.files is None:
+ return True
+
datastore_name, _ = parse_file_path(vm.config.files.vmPathName)
return not datastore_name
--
2.39.5
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2025-07-18 16:18 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-18 16:19 [pve-devel] [PATCH v1 pve-esxi-import-tools 0/5] Type Checking Improvements Max R. Carrara
2025-07-18 16:19 ` Max R. Carrara [this message]
2025-07-18 16:19 ` [pve-devel] [PATCH v1 pve-esxi-import-tools 2/5] listvms: s/EsxiConnectonArgs/EsxiConnectionArgs Max R. Carrara
2025-07-18 16:19 ` [pve-devel] [PATCH v1 pve-esxi-import-tools 3/5] listvms: run formatter Max R. Carrara
2025-07-18 16:19 ` [pve-devel] [PATCH v1 pve-esxi-import-tools 4/5] d/control: add python3-pyvmomi (>= 8) as build dependency Max R. Carrara
2025-07-18 16:19 ` [pve-devel] [PATCH v1 pve-esxi-import-tools 5/5] .gitignore: ignore .lint-incremental Max R. Carrara
2025-07-22 20:14 ` [pve-devel] [PATCH v1 pve-esxi-import-tools 0/5] Type Checking Improvements Thomas Lamprecht
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250718161905.461482-2-m.carrara@proxmox.com \
--to=m.carrara@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.