dissect.btrfs 1.6.dev1__tar.gz → 1.7.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. dissect_btrfs-1.7.dev2/.git-blame-ignore-revs +6 -0
  2. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/PKG-INFO +2 -2
  3. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/btrfs.py +21 -23
  4. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/tree.py +36 -35
  5. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/PKG-INFO +2 -2
  6. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/SOURCES.txt +1 -0
  7. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/pyproject.toml +48 -5
  8. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/conftest.py +10 -5
  9. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/test_btrfs.py +2 -5
  10. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/test_exceptions.py +3 -1
  11. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tox.ini +4 -10
  12. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/.gitattributes +0 -0
  13. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/COPYRIGHT +0 -0
  14. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/LICENSE +0 -0
  15. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/MANIFEST.in +0 -0
  16. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/README.md +0 -0
  17. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/__init__.py +2 -2
  18. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/c_btrfs.py +0 -0
  19. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/exceptions.py +0 -0
  20. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/stream.py +0 -0
  21. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/dependency_links.txt +0 -0
  22. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/requires.txt +0 -0
  23. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/top_level.txt +0 -0
  24. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/setup.cfg +0 -0
  25. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/__init__.py +0 -0
  26. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-compression.bin.gz +0 -0
  27. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-default.bin.gz +0 -0
  28. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-dup-1.bin.gz +0 -0
  29. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-dup-2.bin.gz +0 -0
  30. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid0-1.bin.gz +0 -0
  31. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid0-2.bin.gz +0 -0
  32. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1-1.bin.gz +0 -0
  33. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1-2.bin.gz +0 -0
  34. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid10-1.bin.gz +0 -0
  35. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid10-2.bin.gz +0 -0
  36. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c3-1.bin.gz +0 -0
  37. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c3-2.bin.gz +0 -0
  38. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c3-3.bin.gz +0 -0
  39. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c4-1.bin.gz +0 -0
  40. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c4-2.bin.gz +0 -0
  41. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c4-3.bin.gz +0 -0
  42. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c4-4.bin.gz +0 -0
  43. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid5-1.bin.gz +0 -0
  44. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid5-2.bin.gz +0 -0
  45. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid6-1.bin.gz +0 -0
  46. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid6-2.bin.gz +0 -0
  47. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid6-3.bin.gz +0 -0
  48. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-sparse.bin.gz +0 -0
  49. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume-custom-default.bin.gz +0 -0
  50. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume-nested.bin.gz +0 -0
  51. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume-snapshot.bin.gz +0 -0
  52. {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume.bin.gz +0 -0
@@ -0,0 +1,6 @@
1
+ # Formatting commits. You can ignore them during git-blame with `--ignore-rev` or `--ignore-revs-file`.
2
+ #
3
+ # $ git config --add 'blame.ignoreRevsFile' '.git-blame-ignore-revs'
4
+ #
5
+ # Change linter to Ruff (#20)
6
+ 09742055fb02a6b14dc8f405e3fdf66c1345ba15
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dissect.btrfs
3
- Version: 1.6.dev1
3
+ Version: 1.7.dev2
4
4
  Summary: A Dissect module implementing a parser for the Btrfs file system, a commonly used Linux filesystem.
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License: Affero General Public License v3
@@ -7,9 +7,8 @@ from __future__ import annotations
7
7
 
8
8
  import io
9
9
  import stat
10
- from datetime import datetime
11
10
  from functools import cache, cached_property, lru_cache
12
- from typing import BinaryIO, Iterator, Optional, Union
11
+ from typing import TYPE_CHECKING, BinaryIO
13
12
  from uuid import UUID
14
13
 
15
14
  from dissect.util import ts
@@ -35,6 +34,10 @@ from dissect.btrfs.exceptions import (
35
34
  from dissect.btrfs.stream import ChunkStream, Extent, ExtentStream, decode_extent
36
35
  from dissect.btrfs.tree import BTree
37
36
 
37
+ if TYPE_CHECKING:
38
+ from collections.abc import Iterator
39
+ from datetime import datetime
40
+
38
41
 
39
42
  class Btrfs:
40
43
  """Btrfs filesystem implementation.
@@ -46,7 +49,7 @@ class Btrfs:
46
49
  fh: A file-like object for the volume to use for parsing Btrfs.
47
50
  """
48
51
 
49
- def __init__(self, fh: Union[BinaryIO, list[BinaryIO]]):
52
+ def __init__(self, fh: BinaryIO | list[BinaryIO]):
50
53
  self.fhs = fh if isinstance(fh, list) else [fh]
51
54
 
52
55
  if not self.fhs:
@@ -89,7 +92,7 @@ class Btrfs:
89
92
  self.default_subvolume = self._open_default_subvolume()
90
93
  self.root = self.default_subvolume.root
91
94
 
92
- def get(self, path: Union[str, int], node: Optional[INode] = None) -> INode:
95
+ def get(self, path: str | int, node: INode | None = None) -> INode:
93
96
  """Retrieve a Btrfs inode by path or inode number.
94
97
 
95
98
  Args:
@@ -113,7 +116,7 @@ class Btrfs:
113
116
  yield self.open_subvolume(item.key.offset)
114
117
  cursor.reset()
115
118
 
116
- def find_subvolume(self, path: Optional[str] = None) -> Optional[Subvolume]:
119
+ def find_subvolume(self, path: str | None = None) -> Subvolume | None:
117
120
  """Find a subvolume by path.
118
121
 
119
122
  Args:
@@ -123,7 +126,9 @@ class Btrfs:
123
126
  if subvolume.path == path:
124
127
  return subvolume
125
128
 
126
- def open_subvolume(self, objectid: int, parent: Optional[INode] = None) -> Subvolume:
129
+ return None
130
+
131
+ def open_subvolume(self, objectid: int, parent: INode | None = None) -> Subvolume:
127
132
  """Open a subvolume.
128
133
 
129
134
  Args:
@@ -194,7 +199,7 @@ class Subvolume:
194
199
  parent: Optional parent node to attach to the root of the subvolume.
195
200
  """
196
201
 
197
- def __init__(self, btrfs: Btrfs, objectid: int, parent: Optional[INode] = None):
202
+ def __init__(self, btrfs: Btrfs, objectid: int, parent: INode | None = None):
198
203
  self.btrfs = btrfs
199
204
  self.objectid = objectid
200
205
  self.parent = parent
@@ -234,7 +239,7 @@ class Subvolume:
234
239
 
235
240
  return "/".join(parts[::-1])
236
241
 
237
- def get(self, path: Union[str, int], node: Optional[INode] = None) -> INode:
242
+ def get(self, path: str | int, node: INode | None = None) -> INode:
238
243
  """Retrieve a Btrfs inode by path or inode number.
239
244
 
240
245
  Args:
@@ -286,7 +291,7 @@ class Subvolume:
286
291
 
287
292
  return node
288
293
 
289
- def inode(self, inum: int, type: Optional[int] = None, parent: Optional[INode] = None) -> INode:
294
+ def inode(self, inum: int, type: int | None = None, parent: INode | None = None) -> INode:
290
295
  """Return an :class:`INode` by number, optionally attaching a type and parent."""
291
296
  return INode(self, inum, type, parent)
292
297
 
@@ -312,13 +317,7 @@ class INode:
312
317
  parent: Optional parent of this inode, if this inode is parsed from a directory listing.
313
318
  """
314
319
 
315
- def __init__(
316
- self,
317
- subvolume: Subvolume,
318
- inum: int,
319
- type: Optional[int] = None,
320
- parent: Optional[INode] = None,
321
- ):
320
+ def __init__(self, subvolume: Subvolume, inum: int, type: int | None = None, parent: INode | None = None):
322
321
  self.subvolume = subvolume
323
322
  self.btrfs = subvolume.btrfs
324
323
  self.inum = inum
@@ -450,14 +449,11 @@ class INode:
450
449
  def link_inode(self) -> INode:
451
450
  """Resolve the symlink target to an inode."""
452
451
  link = self.link
453
- if link.startswith("/"):
454
- relnode = None
455
- else:
456
- relnode = self.parent
452
+ relnode = None if link.startswith("/") else self.parent
457
453
  return self.subvolume.get(self.link, relnode)
458
454
 
459
455
  @property
460
- def parents(self) -> list[INode]:
456
+ def parents(self) -> Iterator[INode]:
461
457
  for item, data in self.subvolume.tree.cursor().iter(
462
458
  self.inum, c_btrfs.BTRFS_INODE_REF_KEY, 0, ignore_offset=True
463
459
  ):
@@ -517,7 +513,7 @@ class INode:
517
513
 
518
514
  def listdir(self) -> dict[str, INode]:
519
515
  """Return a directory listing."""
520
- return {name: inode for name, inode in self.iterdir()}
516
+ return dict(self.iterdir())
521
517
 
522
518
  def iterdir(self) -> Iterator[tuple[str, INode]]:
523
519
  """Iterate directory contents."""
@@ -543,11 +539,13 @@ class INode:
543
539
  else:
544
540
  raise NotImplementedError(f"Unknown dir_item type: {dir_item}")
545
541
 
546
- def extents(self) -> Optional[list[Extent]]:
542
+ def extents(self) -> list[Extent] | None:
547
543
  with self.open() as fh:
548
544
  if isinstance(fh, ExtentStream):
549
545
  return fh.extents
550
546
 
547
+ return None
548
+
551
549
  def open(self) -> BinaryIO:
552
550
  """Return the data stream for the inode.
553
551
 
@@ -1,11 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from functools import lru_cache
4
- from typing import TYPE_CHECKING, Iterator, Literal, Optional, Union
4
+ from typing import TYPE_CHECKING, Literal
5
5
 
6
6
  from dissect.btrfs.c_btrfs import c_btrfs
7
7
 
8
8
  if TYPE_CHECKING:
9
+ from collections.abc import Iterator
10
+
9
11
  from dissect.btrfs.btrfs import Btrfs
10
12
 
11
13
 
@@ -20,9 +22,7 @@ class BTree:
20
22
  root_offset: Optional offset to open the B-tree from.
21
23
  """
22
24
 
23
- def __init__(
24
- self, btrfs: Btrfs, root_item: Optional[c_btrfs.btrfs_root_item] = None, root_offset: Optional[int] = None
25
- ):
25
+ def __init__(self, btrfs: Btrfs, root_item: c_btrfs.btrfs_root_item | None = None, root_offset: int | None = None):
26
26
  self.btrfs = btrfs
27
27
 
28
28
  if not root_item and not root_offset:
@@ -38,7 +38,7 @@ class BTree:
38
38
  return Cursor(self)
39
39
 
40
40
  def find(
41
- self, objectid: Optional[int] = None, type: Optional[int] = None, offset: Optional[int] = None
41
+ self, objectid: int | None = None, type: int | None = None, offset: int | None = None
42
42
  ) -> tuple[c_btrfs.btrfs_item, memoryview]:
43
43
  """Search for a single item in the B-tree.
44
44
 
@@ -127,7 +127,7 @@ class Cursor:
127
127
 
128
128
  return key
129
129
 
130
- def _read_item(self, index: int) -> Union[c_btrfs.btrfs_key_ptr, c_btrfs.btrfs_item]:
130
+ def _read_item(self, index: int) -> c_btrfs.btrfs_key_ptr | c_btrfs.btrfs_item:
131
131
  """Read an item at the specified index.
132
132
 
133
133
  Args:
@@ -214,7 +214,7 @@ class Cursor:
214
214
  """
215
215
  return self.item(), self.data()
216
216
 
217
- def item(self) -> Union[c_btrfs.btrfs_key_ptr, c_btrfs.btrfs_item]:
217
+ def item(self) -> c_btrfs.btrfs_key_ptr | c_btrfs.btrfs_item:
218
218
  """Retrieve a leaf or branch item.
219
219
 
220
220
  Cursor can be positioned at a branch or leaf item.
@@ -224,9 +224,9 @@ class Cursor:
224
224
 
225
225
  return self._read_item(self._index)
226
226
 
227
- def items(self) -> Iterator[Union[c_btrfs.btrfs_key_ptr, c_btrfs.btrfs_item]]:
227
+ def items(self) -> Iterator[c_btrfs.btrfs_key_ptr | c_btrfs.btrfs_item]:
228
228
  """Iterate over all items in the current node."""
229
- for i in range(0, self._header.nritems):
229
+ for i in range(self._header.nritems):
230
230
  yield self._read_item(i)
231
231
 
232
232
  def data(self) -> memoryview:
@@ -245,9 +245,9 @@ class Cursor:
245
245
 
246
246
  def iter(
247
247
  self,
248
- objectid: Optional[int] = None,
249
- type: Optional[int] = None,
250
- offset: Optional[int] = None,
248
+ objectid: int | None = None,
249
+ type: int | None = None,
250
+ offset: int | None = None,
251
251
  ignore_offset: bool = False,
252
252
  ) -> Iterator[tuple[c_btrfs.btrfs_item, memoryview]]:
253
253
  """Search and iterate the B-tree for the specified key.
@@ -274,9 +274,9 @@ class Cursor:
274
274
 
275
275
  def walk(
276
276
  self,
277
- objectid: Optional[int] = None,
278
- type: Optional[int] = None,
279
- offset: Optional[int] = None,
277
+ objectid: int | None = None,
278
+ type: int | None = None,
279
+ offset: int | None = None,
280
280
  ) -> Iterator[tuple[c_btrfs.btrfs_item, memoryview]]:
281
281
  """Walk all leaf items of the B-tree and yield all matching leafs.
282
282
 
@@ -296,7 +296,7 @@ class Cursor:
296
296
  except ValueError:
297
297
  return
298
298
 
299
- def search(self, objectid: Optional[int] = None, type: Optional[int] = None, offset: Optional[int] = None) -> bool:
299
+ def search(self, objectid: int | None = None, type: int | None = None, offset: int | None = None) -> bool:
300
300
  """Perform a binary search on the current node for the key with the given parameters.
301
301
 
302
302
  Puts the cursor at the index of the matching item, or just before a "greater" item if no exact match is found.
@@ -330,22 +330,23 @@ class Cursor:
330
330
  self._index = min_idx
331
331
  self.push(self._read_item(min_idx).blockptr)
332
332
  continue
333
- else:
334
- if result >= 0:
335
- # Count a matching or larger key as a win
336
- self._index = min_idx
337
- return True
338
- elif min_idx == self._header.nritems - 1:
339
- # Special case where we have exhausted all leaf nodes but all keys are still smaller
340
- # In this case, try to travel to the next node (up one level, next item, down one level)
341
- # Worst case we end up at a key that's larger than our search parameters.
342
- self._index = min_idx
343
- try:
344
- self.next_node()
345
- continue
346
- except ValueError:
347
- self._index = None
348
- return False
333
+
334
+ if result >= 0:
335
+ # Count a matching or larger key as a win
336
+ self._index = min_idx
337
+ return True
338
+
339
+ if min_idx == self._header.nritems - 1:
340
+ # Special case where we have exhausted all leaf nodes but all keys are still smaller
341
+ # In this case, try to travel to the next node (up one level, next item, down one level)
342
+ # Worst case we end up at a key that's larger than our search parameters.
343
+ self._index = min_idx
344
+ try:
345
+ self.next_node()
346
+ continue
347
+ except ValueError:
348
+ self._index = None
349
+ return False
349
350
 
350
351
  break
351
352
 
@@ -355,9 +356,9 @@ class Cursor:
355
356
 
356
357
  def _cmp_key(
357
358
  key: c_btrfs.btrfs_disk_key,
358
- objectid: Optional[int] = None,
359
- type: Optional[int] = None,
360
- offset: Optional[int] = None,
359
+ objectid: int | None = None,
360
+ type: int | None = None,
361
+ offset: int | None = None,
361
362
  ) -> Literal[1, -1, 0]:
362
363
  """Compare a B-tree key on disk to a given object ID, type and offset.
363
364
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dissect.btrfs
3
- Version: 1.6.dev1
3
+ Version: 1.7.dev2
4
4
  Summary: A Dissect module implementing a parser for the Btrfs file system, a commonly used Linux filesystem.
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License: Affero General Public License v3
@@ -1,3 +1,4 @@
1
+ .git-blame-ignore-revs
1
2
  .gitattributes
2
3
  COPYRIGHT
3
4
  LICENSE
@@ -53,13 +53,56 @@ dev = [
53
53
  "dissect.util>=3.0.dev,<4.0.dev",
54
54
  ]
55
55
 
56
- [tool.black]
56
+ [tool.ruff]
57
57
  line-length = 120
58
+ required-version = ">=0.9.0"
58
59
 
59
- [tool.isort]
60
- profile = "black"
61
- known_first_party = ["dissect.btrfs"]
62
- known_third_party = ["dissect"]
60
+ [tool.ruff.format]
61
+ docstring-code-format = true
62
+
63
+ [tool.ruff.lint]
64
+ select = [
65
+ "F",
66
+ "E",
67
+ "W",
68
+ "I",
69
+ "UP",
70
+ "YTT",
71
+ "ANN",
72
+ "B",
73
+ "C4",
74
+ "DTZ",
75
+ "T10",
76
+ "FA",
77
+ "ISC",
78
+ "G",
79
+ "INP",
80
+ "PIE",
81
+ "PYI",
82
+ "PT",
83
+ "Q",
84
+ "RSE",
85
+ "RET",
86
+ "SLOT",
87
+ "SIM",
88
+ "TID",
89
+ "TCH",
90
+ "PTH",
91
+ "PLC",
92
+ "TRY",
93
+ "FLY",
94
+ "PERF",
95
+ "FURB",
96
+ "RUF",
97
+ ]
98
+ ignore = ["E203", "B904", "UP024", "ANN002", "ANN003", "ANN204", "ANN401", "SIM105", "TRY003"]
99
+
100
+ [tool.ruff.lint.per-file-ignores]
101
+ "tests/docs/**" = ["INP001"]
102
+
103
+ [tool.ruff.lint.isort]
104
+ known-first-party = ["dissect.btrfs"]
105
+ known-third-party = ["dissect"]
63
106
 
64
107
  [tool.setuptools]
65
108
  license-files = ["LICENSE", "COPYRIGHT"]
@@ -1,17 +1,22 @@
1
+ from __future__ import annotations
2
+
1
3
  import contextlib
2
4
  import gzip
3
- import os
4
- from typing import IO, BinaryIO, Iterator
5
+ from pathlib import Path
6
+ from typing import IO, TYPE_CHECKING, BinaryIO
5
7
 
6
8
  import pytest
7
9
 
10
+ if TYPE_CHECKING:
11
+ from collections.abc import Iterator
12
+
8
13
 
9
- def absolute_path(filename: str) -> str:
10
- return os.path.join(os.path.dirname(__file__), filename)
14
+ def absolute_path(filename: str) -> Path:
15
+ return Path(__file__).parent / filename
11
16
 
12
17
 
13
18
  def open_file(name: str, mode: str = "rb") -> Iterator[IO]:
14
- with open(absolute_path(name), mode) as f:
19
+ with absolute_path(name).open(mode) as f:
15
20
  yield f
16
21
 
17
22
 
@@ -200,11 +200,8 @@ def test_btrfs_profiles(fixture: str, request: pytest.FixtureRequest) -> None:
200
200
  )
201
201
  def test_btrfs_profiles_partial(fixture: str, request: pytest.FixtureRequest) -> None:
202
202
  fhs = request.getfixturevalue(fixture)
203
- if fixture == "btrfs_profile_dup":
204
- # This test data just so happens to have all chunks on the second device
205
- fhs = fhs[:-1]
206
- else:
207
- fhs = fhs[1:]
203
+ # The btrfs_profile_dup test data just so happens to have all chunks on the second device
204
+ fhs = fhs[:-1] if fixture == "btrfs_profile_dup" else fhs[1:]
208
205
 
209
206
  if fixture in ("btrfs_profile_dup", "btrfs_profile_raid0"):
210
207
  with pytest.raises(Error, match="Missing stripe disk for chunk offset .+"):
@@ -1,10 +1,12 @@
1
+ from __future__ import annotations
2
+
1
3
  import pytest
2
4
 
3
5
  from dissect.btrfs import exceptions
4
6
 
5
7
 
6
8
  @pytest.mark.parametrize(
7
- "exc, std",
9
+ ("exc", "std"),
8
10
  [
9
11
  (exceptions.FileNotFoundError, FileNotFoundError),
10
12
  (exceptions.IsADirectoryError, IsADirectoryError),
@@ -32,23 +32,17 @@ commands =
32
32
  [testenv:fix]
33
33
  package = skip
34
34
  deps =
35
- black==23.1.0
36
- isort==5.11.4
35
+ ruff==0.9.2
37
36
  commands =
38
- black dissect tests
39
- isort dissect tests
37
+ ruff format dissect tests
40
38
 
41
39
  [testenv:lint]
42
40
  package = skip
43
41
  deps =
44
- black==23.1.0
45
- flake8
46
- flake8-black
47
- flake8-isort
48
- isort==5.11.4
42
+ ruff==0.9.2
49
43
  vermin
50
44
  commands =
51
- flake8 dissect tests
45
+ ruff check dissect tests
52
46
  vermin -t=3.9- --no-tips --lint dissect tests
53
47
 
54
48
  [flake8]
@@ -8,10 +8,10 @@ from dissect.btrfs.exceptions import (
8
8
 
9
9
  __all__ = [
10
10
  "Btrfs",
11
- "INode",
12
- "Subvolume",
13
11
  "Error",
14
12
  "FileNotFoundError",
13
+ "INode",
15
14
  "NotADirectoryError",
16
15
  "NotASymlinkError",
16
+ "Subvolume",
17
17
  ]