Skip to content

Commit

Permalink
Change linter to Ruff (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
Schamper authored Jan 21, 2025
1 parent 9b0df29 commit b1ed30e
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 63 deletions.
4 changes: 2 additions & 2 deletions dissect/extfs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
from dissect.extfs.journal import JDB2

__all__ = [
"ExtFS",
"INode",
"JDB2",
"Error",
"ExtFS",
"FileNotFoundError",
"INode",
"NotADirectoryError",
"NotASymlinkError",
]
2 changes: 2 additions & 0 deletions dissect/extfs/c_ext.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import stat

from dissect.cstruct import cstruct
Expand Down
2 changes: 2 additions & 0 deletions dissect/extfs/c_jdb2.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from dissect.cstruct import cstruct

jdb2_def = """
Expand Down
58 changes: 29 additions & 29 deletions dissect/extfs/extfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
import logging
import os
import stat
from datetime import datetime
from functools import lru_cache
from typing import BinaryIO, Iterator, Optional, Union
from typing import TYPE_CHECKING, BinaryIO
from uuid import UUID

from dissect.util import ts
Expand All @@ -29,6 +28,10 @@
)
from dissect.extfs.journal import JDB2

if TYPE_CHECKING:
from collections.abc import Iterator
from datetime import datetime

log = logging.getLogger(__name__)
log.setLevel(os.getenv("DISSECT_LOG_EXTFS", "CRITICAL"))

Expand Down Expand Up @@ -114,7 +117,7 @@ def journal(self) -> JDB2:

return self._journal

def get(self, path: Union[str, int], node: Optional[INode] = None) -> INode:
def get(self, path: str | int, node: INode | None = None) -> INode:
if isinstance(path, int):
return self.get_inode(path)

Expand All @@ -139,9 +142,9 @@ def get(self, path: Union[str, int], node: Optional[INode] = None) -> INode:
def get_inode(
self,
inum: int,
filename: Optional[str] = None,
filetype: Optional[int] = None,
parent: Optional[INode] = None,
filename: str | None = None,
filetype: int | None = None,
parent: INode | None = None,
lazy: bool = False,
) -> INode:
if inum < c_ext.EXT2_BAD_INO or inum > self.sb.s_inodes_count:
Expand Down Expand Up @@ -181,9 +184,9 @@ def __init__(
self,
extfs: ExtFS,
inum: int,
filename: Optional[str] = None,
filetype: Optional[int] = None,
parent: Optional[INode] = None,
filename: str | None = None,
filetype: int | None = None,
parent: INode | None = None,
):
self.extfs = extfs
self.inum = inum
Expand Down Expand Up @@ -248,10 +251,7 @@ def link_inode(self) -> INode:
if not self._link_inode:
# Relative lookups work because . and .. are actual directory entries
link = self.link
if link.startswith("/"):
relnode = None
else:
relnode = self.parent
relnode = None if link.startswith("/") else self.parent
self._link_inode = self.extfs.get(self.link, relnode)
return self._link_inode

Expand Down Expand Up @@ -320,14 +320,14 @@ def dtime(self) -> datetime:
return ts.from_unix(self.inode.i_dtime)

@property
def crtime(self) -> Optional[datetime]:
def crtime(self) -> datetime | None:
time_ns = self.crtime_ns
if time_ns is None:
return None
return ts.from_unix_ns(time_ns)

@property
def crtime_ns(self) -> Optional[int]:
def crtime_ns(self) -> int | None:
if self.extfs.sb.s_inode_size <= 128:
return None

Expand Down Expand Up @@ -370,7 +370,7 @@ def iterdir(self) -> Iterator[INode]:
offset += direntry.rec_len
buf.seek(offset)

def dataruns(self) -> list[tuple[Optional[int], int]]:
def dataruns(self) -> list[tuple[int | None, int]]:
if not self._runlist:
expected_runs = (self.size + self.extfs.block_size - 1) // self.extfs.block_size

Expand Down Expand Up @@ -446,7 +446,7 @@ def dataruns(self) -> list[tuple[Optional[int], int]]:
return self._runlist

def open(self) -> BinaryIO:
if self.inode.i_flags & c_ext.EXT4_INLINE_DATA_FL or self.filetype == stat.S_IFLNK and self.size < 60:
if self.inode.i_flags & c_ext.EXT4_INLINE_DATA_FL or (self.filetype == stat.S_IFLNK and self.size < 60):
buf = io.BytesIO(memoryview(self.inode.i_block)[: self.size])
# Need to add a size attribute to maintain compatibility with dissect streams
buf.size = self.size
Expand Down Expand Up @@ -478,21 +478,21 @@ def _parse_indirect(inode: INode, offset: int, num_blocks: int, level: int) -> l
return [0] * read_blocks
inode.extfs.fh.seek(offset * inode.extfs.block_size)
return c_ext.uint32[read_blocks](inode.extfs.fh)
else:
blocks = []

max_level_blocks = offsets_per_block**level
blocks_per_nest = max_level_blocks // offsets_per_block
read_blocks = (num_blocks + blocks_per_nest - 1) // blocks_per_nest
read_blocks = min(read_blocks, offsets_per_block)
blocks = []

inode.extfs.fh.seek(offset * inode.extfs.block_size)
for addr in c_ext.uint32[read_blocks](inode.extfs.fh):
parsed_blocks = _parse_indirect(inode, addr, num_blocks, level - 1)
num_blocks -= len(parsed_blocks)
blocks.extend(parsed_blocks)
max_level_blocks = offsets_per_block**level
blocks_per_nest = max_level_blocks // offsets_per_block
read_blocks = (num_blocks + blocks_per_nest - 1) // blocks_per_nest
read_blocks = min(read_blocks, offsets_per_block)

inode.extfs.fh.seek(offset * inode.extfs.block_size)
for addr in c_ext.uint32[read_blocks](inode.extfs.fh):
parsed_blocks = _parse_indirect(inode, addr, num_blocks, level - 1)
num_blocks -= len(parsed_blocks)
blocks.extend(parsed_blocks)

return blocks
return blocks


def _parse_extents(inode: INode, buf: bytes) -> Iterator[c_ext.ext4_extent]:
Expand Down
9 changes: 6 additions & 3 deletions dissect/extfs/journal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import datetime
import io
from typing import BinaryIO, Iterator, Optional
from typing import TYPE_CHECKING, BinaryIO

from dissect.util.stream import RangeStream

from dissect.extfs.c_jdb2 import c_jdb2
from dissect.extfs.exceptions import Error

if TYPE_CHECKING:
from collections.abc import Iterator


class JDB2:
def __init__(self, fh: BinaryIO):
Expand Down Expand Up @@ -132,15 +135,15 @@ def __init__(
jdb2: JDB2,
header: c_jdb2.commit_header,
journal_block: int,
descriptors: Optional[list[DescriptorBlock]] = None,
descriptors: list[DescriptorBlock] | None = None,
):
self.jdb2 = jdb2
self.header = header
self.journal_block = journal_block
self.descriptors = descriptors if descriptors else []

self.sequence = self.header.h_sequence
self.ts = datetime.datetime.utcfromtimestamp(self.header.h_commit_sec)
self.ts = datetime.datetime.fromtimestamp(self.header.h_commit_sec, tz=datetime.timezone.utc)
self.ts += datetime.timedelta(microseconds=self.header.h_commit_nsec // 1000)

def __repr__(self) -> str:
Expand Down
53 changes: 48 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,56 @@ dev = [
"dissect.util>=3.0.dev,<4.0.dev",
]

[tool.black]
[tool.ruff]
line-length = 120
required-version = ">=0.9.0"

[tool.isort]
profile = "black"
known_first_party = ["dissect.extfs"]
known_third_party = ["dissect"]
[tool.ruff.format]
docstring-code-format = true

[tool.ruff.lint]
select = [
"F",
"E",
"W",
"I",
"UP",
"YTT",
"ANN",
"B",
"C4",
"DTZ",
"T10",
"FA",
"ISC",
"G",
"INP",
"PIE",
"PYI",
"PT",
"Q",
"RSE",
"RET",
"SLOT",
"SIM",
"TID",
"TCH",
"PTH",
"PLC",
"TRY",
"FLY",
"PERF",
"FURB",
"RUF",
]
ignore = ["E203", "B904", "UP024", "ANN002", "ANN003", "ANN204", "ANN401", "SIM105", "TRY003"]

[tool.ruff.lint.per-file-ignores]
"tests/docs/**" = ["INP001"]

[tool.ruff.lint.isort]
known-first-party = ["dissect.extfs"]
known-third-party = ["dissect"]

[tool.setuptools]
license-files = ["LICENSE", "COPYRIGHT"]
Expand Down
15 changes: 10 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
from __future__ import annotations

import gzip
import os
from typing import BinaryIO, Iterator
from pathlib import Path
from typing import TYPE_CHECKING, BinaryIO

import pytest

if TYPE_CHECKING:
from collections.abc import Iterator


def absolute_path(filename) -> str:
return os.path.join(os.path.dirname(__file__), filename)
def absolute_path(filename: str) -> Path:
return Path(__file__).parent / filename


def gzip_file(filename) -> Iterator[BinaryIO]:
def gzip_file(filename: str) -> Iterator[BinaryIO]:
with gzip.GzipFile(absolute_path(filename), "rb") as fh:
yield fh

Expand Down
4 changes: 3 additions & 1 deletion tests/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from __future__ import annotations

import pytest

from dissect.extfs import exceptions


@pytest.mark.parametrize(
"exc, std",
("exc", "std"),
[
(exceptions.FileNotFoundError, FileNotFoundError),
(exceptions.IsADirectoryError, IsADirectoryError),
Expand Down
20 changes: 12 additions & 8 deletions tests/test_ext4.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
from __future__ import annotations

import datetime
import gzip
import stat
from io import BytesIO
from logging import Logger
from typing import BinaryIO
from typing import TYPE_CHECKING, BinaryIO
from unittest.mock import call, patch

import pytest

from dissect.extfs.c_ext import c_ext
from dissect.extfs.extfs import EXT4, ExtFS, INode

if TYPE_CHECKING:
from logging import Logger


def test_ext4(ext4_bin: BinaryIO):
def test_ext4(ext4_bin: BinaryIO) -> None:
extfs = ExtFS(ext4_bin)

assert extfs.type == EXT4
Expand Down Expand Up @@ -43,7 +47,7 @@ def test_ext4(ext4_bin: BinaryIO):
assert len(list(extfs.journal.commits())) == 2


def test_xattr(ext4_bin: BinaryIO):
def test_xattr(ext4_bin: BinaryIO) -> None:
e = ExtFS(ext4_bin)

inode = e.get("xattr_cap")
Expand All @@ -56,7 +60,7 @@ def test_xattr(ext4_bin: BinaryIO):
assert xattrs[1].value == b"\x01\x00\x00\x02\x00\x04@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"


def test_sparse(ext4_sparse_bin: BinaryIO):
def test_sparse(ext4_sparse_bin: BinaryIO) -> None:
extfs = ExtFS(ext4_sparse_bin)

sparse_start = extfs.get("sparse_start")
Expand Down Expand Up @@ -84,11 +88,11 @@ def test_sparse(ext4_sparse_bin: BinaryIO):
("tests/data/ext4_symlink_test3.bin.gz"),
],
)
def test_symlinks(image_file: str):
def test_symlinks(image_file: str) -> None:
path = "/path/to/dir/with/file.ext"
expect = b"resolved!\n"

def resolve(node):
def resolve(node: INode) -> INode:
while node.filetype == stat.S_IFLNK:
node = node.link_inode
return node
Expand All @@ -100,7 +104,7 @@ def resolve(node):
@patch("dissect.extfs.extfs.INode.open", return_value=BytesIO(b"\x00" * 16))
@patch("dissect.extfs.extfs.log", create=True, return_value=None)
@patch("dissect.extfs.extfs.ExtFS")
def test_infinite_loop_protection(ExtFS: ExtFS, log: Logger, *args):
def test_infinite_loop_protection(ExtFS: ExtFS, log: Logger, *args) -> None:
ExtFS.sb.s_inodes_count = 69
ExtFS._dirtype = c_ext.ext2_dir_entry_2
inode = INode(ExtFS, 1, filetype=stat.S_IFDIR)
Expand Down
14 changes: 4 additions & 10 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,17 @@ commands =
[testenv:fix]
package = skip
deps =
black==23.1.0
isort==5.11.4
ruff==0.9.2
commands =
black dissect tests
isort dissect tests
ruff format dissect tests

[testenv:lint]
package = skip
deps =
black==23.1.0
flake8
flake8-black
flake8-isort
isort==5.11.4
ruff==0.9.2
vermin
commands =
flake8 dissect tests
ruff check dissect tests
vermin -t=3.9- --no-tips --lint dissect tests

[flake8]
Expand Down

0 comments on commit b1ed30e

Please sign in to comment.