From 92bb401b9751649e7960446bdd7e1ef49e1e1637 Mon Sep 17 00:00:00 2001 From: wbi Date: Fri, 27 Mar 2026 09:35:02 +0100 Subject: [PATCH 1/2] Add stricter rules (doctstyle) + Add annotations import to ruff isort required imports. ruff check --fix dissect tests --- dissect/hypervisor/__init__.py | 2 ++ dissect/hypervisor/descriptor/vmx.py | 8 +------- dissect/hypervisor/disk/vmdk.py | 5 +---- dissect/hypervisor/exceptions.py | 3 +++ dissect/hypervisor/tools/vmtar.py | 2 ++ dissect/hypervisor/util/vmtar.py | 4 ++-- pyproject.toml | 20 +++++++++++++++++++- tests/_docs/conf.py | 2 ++ tests/disk/test_vmdk.py | 3 +-- 9 files changed, 33 insertions(+), 16 deletions(-) diff --git a/dissect/hypervisor/__init__.py b/dissect/hypervisor/__init__.py index 53294ba..aa22d24 100644 --- a/dissect/hypervisor/__init__.py +++ b/dissect/hypervisor/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from dissect.hypervisor.descriptor import hyperv, ovf, pvs, vbox, vmx from dissect.hypervisor.disk import asif, hdd, qcow2, vdi, vhd, vhdx, vmdk from dissect.hypervisor.util import envelope, vmtar diff --git a/dissect/hypervisor/descriptor/vmx.py b/dissect/hypervisor/descriptor/vmx.py index c51bae3..b97dcfc 100644 --- a/dissect/hypervisor/descriptor/vmx.py +++ b/dissect/hypervisor/descriptor/vmx.py @@ -101,7 +101,7 @@ def unlock_with_phrase(self, passphrase: str) -> None: self.attr.update(**_parse_dictionary(decrypted.decode())) def disks(self) -> list[str]: - """Return a list of paths to disk files""" + """Return a list of paths to disk files.""" dev_classes = ("scsi", "sata", "ide", "nvme") devices = {} @@ -179,7 +179,6 @@ def unseal_with_phrase(self, passphrase: str) -> bytes: @classmethod def from_text(cls, text: str) -> KeySafe: """Parse a ``KeySafe`` from a string.""" - # Key safes are a list of key locators. It's a key locator string with a specific prefix identifier, _, remainder = text.partition("/") if identifier != "vmware:key": @@ -262,7 +261,6 @@ def _parse_key_locator(locator_string: str) -> Pair | Phrase | list[Pair | Phras Interally called ``KeyLocator``. """ - identifier, _, remainder = locator_string.partition("/") if identifier == "list": @@ -303,7 +301,6 @@ def _split_list(value: str) -> list[str]: Lists are wrapped by braces and separated by comma. They can contain nested lists/pairs, so we need to separate at the correct nest level. """ - if not (match := re.match(r"\((.+)\)", value)): raise ValueError("Invalid list string") @@ -337,7 +334,6 @@ def _parse_crypto_dict(dict_string: str) -> dict[str, str]: Internally called ``CryptoDict``. """ - crypto_dict = {} for part in dict_string.split(":"): key, _, value = part.partition("=") @@ -351,7 +347,6 @@ def _decrypt_hmac(key: bytes, data: bytes, digest: str) -> bytes: First 16 bytes of the ciphertext are the IV and the last N bytes are the HMAC digest. The cleartext is padded using PKCS#7. """ - digest, digest_size = HMAC_MAP[digest] iv, encrypted, mac = data[:16], data[16:-digest_size], data[-digest_size:] @@ -374,7 +369,6 @@ def _create_cipher(key: bytes, iv: bytes) -> AES.CbcMode: Dynamic based on the available crypto module. """ - if HAS_PYSTANDALONE: if len(key) == 32: cipher = "aes-256-cbc" diff --git a/dissect/hypervisor/disk/vmdk.py b/dissect/hypervisor/disk/vmdk.py index 8af096a..5f88a23 100644 --- a/dissect/hypervisor/disk/vmdk.py +++ b/dissect/hypervisor/disk/vmdk.py @@ -29,9 +29,7 @@ class VMDK(AlignedStream): def __init__(self, fh: BinaryIO | Path | str | list[BinaryIO | Path | str]): - """ - Input can be a file handle to a Disk Descriptor file or a list of file handles to multiple VMDK files. - """ + """Input can be a file handle to a Disk Descriptor file or a list of file handles to multiple VMDK files.""" fhs = [fh] if not isinstance(fh, list) else fh self.disks = [] @@ -462,7 +460,6 @@ def parse(cls, vmdk_config: str) -> DiskDescriptor: Resources: - https://github.com/libyal/libvmdk/blob/main/documentation/VMWare%20Virtual%20Disk%20Format%20(VMDK).asciidoc """ - descriptor_settings = {} extents: list[ExtentDescriptor] = [] disk_db = {} diff --git a/dissect/hypervisor/exceptions.py b/dissect/hypervisor/exceptions.py index d696298..e49a6af 100644 --- a/dissect/hypervisor/exceptions.py +++ b/dissect/hypervisor/exceptions.py @@ -1,3 +1,6 @@ +from __future__ import annotations + + class Error(Exception): pass diff --git a/dissect/hypervisor/tools/vmtar.py b/dissect/hypervisor/tools/vmtar.py index 854da25..8359801 100644 --- a/dissect/hypervisor/tools/vmtar.py +++ b/dissect/hypervisor/tools/vmtar.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import tarfile from dissect.hypervisor.util import vmtar diff --git a/dissect/hypervisor/util/vmtar.py b/dissect/hypervisor/util/vmtar.py index 329bdc9..e52f8cc 100644 --- a/dissect/hypervisor/util/vmtar.py +++ b/dissect/hypervisor/util/vmtar.py @@ -62,12 +62,12 @@ def visoropen(cls, name: str, mode: str = "r", fileobj: BinaryIO | None = None, raise tarfile.TarError("visor currently only supports read mode") try: - from gzip import GzipFile # noqa: PLC0415 + from gzip import GzipFile except ImportError: raise tarfile.CompressionError("gzip module is not available") from None try: - from lzma import LZMAError, LZMAFile # noqa: PLC0415 + from lzma import LZMAError, LZMAFile except ImportError: raise tarfile.CompressionError("lzma module is not available") from None diff --git a/pyproject.toml b/pyproject.toml index c7055c5..c147ecd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -113,8 +113,25 @@ select = [ "PERF", "FURB", "RUF", + "D" ] -ignore = ["E203", "B904", "UP024", "ANN002", "ANN003", "ANN204", "ANN401", "SIM105", "TRY003"] +ignore = [ + "E203", "B904", "UP024", "ANN002", "ANN003", "ANN204", "ANN401", "SIM105", "TRY003", "PLC0415", + # Ignore some pydocstyle rules for now as they require a larger cleanup + "D1", + "D205", + "D301", + "D417", + # Seems bugged: https://github.com/astral-sh/ruff/issues/16824 + "D402", +] +future-annotations = true + +[tool.ruff.lint.pydocstyle] +convention = "google" + +[tool.ruff.lint.flake8-type-checking] +strict = true [tool.ruff.lint.per-file-ignores] "tests/_docs/**" = ["INP001"] @@ -123,6 +140,7 @@ ignore = ["E203", "B904", "UP024", "ANN002", "ANN003", "ANN204", "ANN401", "SIM1 [tool.ruff.lint.isort] known-first-party = ["dissect.hypervisor"] known-third-party = ["dissect"] +required-imports = ["from __future__ import annotations"] [tool.setuptools.packages.find] include = ["dissect.*"] diff --git a/tests/_docs/conf.py b/tests/_docs/conf.py index dc56239..3d0369d 100644 --- a/tests/_docs/conf.py +++ b/tests/_docs/conf.py @@ -1,3 +1,5 @@ +from __future__ import annotations + project = "dissect.hypervisor" extensions = [ diff --git a/tests/disk/test_vmdk.py b/tests/disk/test_vmdk.py index 13aea51..269aad9 100644 --- a/tests/disk/test_vmdk.py +++ b/tests/disk/test_vmdk.py @@ -197,12 +197,11 @@ def test_vmdk_sesparse() -> None: ), ) def test_vmdk_extent_description(extent_description: str, expected_extents: list[ExtentDescriptor]) -> None: - """test if we correctly parse VMDK sparse and flat extent descriptions. + """Test if we correctly parse VMDK sparse and flat extent descriptions. Resources: - https://github.com/libyal/libvmdk/blob/main/documentation/VMWare%20Virtual%20Disk%20Format%20(VMDK).asciidoc#22-extent-descriptions """ - descriptor = DiskDescriptor.parse(extent_description) assert descriptor.extents == expected_extents From 518d3ef0602b2f8adeec8ad8a935cdb2cd9e9a05 Mon Sep 17 00:00:00 2001 From: wbi Date: Fri, 27 Mar 2026 09:41:30 +0100 Subject: [PATCH 2/2] Rename ruff rule TCH -> TC --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c147ecd..78f9bf7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,7 +105,7 @@ select = [ "SLOT", "SIM", "TID", - "TCH", + "TC", "PTH", "PLC", "TRY",