multiarchive 0.2.1__tar.gz → 0.2.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: multiarchive
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A high level archive handler for Python.
5
5
  Author: NSPC911
6
6
  Author-email: NSPC911 <87571998+NSPC911@users.noreply.github.com>
@@ -222,6 +222,8 @@ The `infolist()` method returns `ArchiveMemberInfo` objects with a unified inter
222
222
  | `mtime` | `float` | Modification time as epoch seconds |
223
223
  | `mode` | `int \| None` | Unix permission bits |
224
224
  | `is_dir` | `bool` | Whether the member is a directory |
225
+ | `kind` | `Literal["file", "directory", "symlink", "junction", "hardlink", "fifo", "character-device", "block-device", "unknown"]` | Member type |
226
+ | `link_target` | `str \| None` | Symlink, junction, or hardlink target when available |
225
227
  | `raw` | `ZipInfo \| TarInfo \| RarInfo \| None` | Original backend object (`None` for plain compressed files) |
226
228
 
227
229
  Factory methods for direct conversion (you shouldn't need these in normal usage):
@@ -213,6 +213,8 @@ The `infolist()` method returns `ArchiveMemberInfo` objects with a unified inter
213
213
  | `mtime` | `float` | Modification time as epoch seconds |
214
214
  | `mode` | `int \| None` | Unix permission bits |
215
215
  | `is_dir` | `bool` | Whether the member is a directory |
216
+ | `kind` | `Literal["file", "directory", "symlink", "junction", "hardlink", "fifo", "character-device", "block-device", "unknown"]` | Member type |
217
+ | `link_target` | `str \| None` | Symlink, junction, or hardlink target when available |
216
218
  | `raw` | `ZipInfo \| TarInfo \| RarInfo \| None` | Original backend object (`None` for plain compressed files) |
217
219
 
218
220
  Factory methods for direct conversion (you shouldn't need these in normal usage):
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "multiarchive"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "A high level archive handler for Python."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "multiarchive"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "A high level archive handler for Python."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -1,3 +1,4 @@
1
+ import stat
1
2
  import sys
2
3
  import zipfile
3
4
  from dataclasses import dataclass
@@ -74,6 +75,33 @@ else:
74
75
  Algos: TypeAlias = Literal[
75
76
  "zip", "tar", "rar", "tar.gz", "tar.bz2", "tar.xz", "tar.zst"
76
77
  ]
78
+ ArchiveMemberKind: TypeAlias = Literal[
79
+ "file",
80
+ "directory",
81
+ "symlink",
82
+ "junction",
83
+ "hardlink",
84
+ "fifo",
85
+ "character-device",
86
+ "block-device",
87
+ "unknown",
88
+ ]
89
+
90
+
91
+ def _kind_from_mode(mode: int | None) -> ArchiveMemberKind | None:
92
+ if mode is None:
93
+ return None
94
+ return cast(
95
+ ArchiveMemberKind | None,
96
+ {
97
+ stat.S_IFREG: "file",
98
+ stat.S_IFDIR: "directory",
99
+ stat.S_IFLNK: "symlink",
100
+ stat.S_IFIFO: "fifo",
101
+ stat.S_IFCHR: "character-device",
102
+ stat.S_IFBLK: "block-device",
103
+ }.get(stat.S_IFMT(mode)),
104
+ )
77
105
 
78
106
 
79
107
  class BadArchiveError(RuntimeError):
@@ -107,6 +135,8 @@ class ArchiveMemberInfo:
107
135
  mtime: float
108
136
  mode: int | None
109
137
  is_dir: bool
138
+ kind: ArchiveMemberKind
139
+ link_target: str | None
110
140
  raw: InfoType | None
111
141
 
112
142
  @classmethod
@@ -119,6 +149,12 @@ class ArchiveMemberInfo:
119
149
  mtime=mtime_dt.timestamp(),
120
150
  mode=(info.external_attr >> 16) or None,
121
151
  is_dir=info.is_dir(),
152
+ kind=(
153
+ "directory"
154
+ if info.is_dir()
155
+ else _kind_from_mode(info.external_attr >> 16) or "file"
156
+ ),
157
+ link_target=None,
122
158
  raw=info,
123
159
  )
124
160
 
@@ -131,11 +167,30 @@ class ArchiveMemberInfo:
131
167
  mtime=float(info.mtime or 0.0),
132
168
  mode=info.mode,
133
169
  is_dir=info.isdir(),
170
+ kind=(
171
+ "file"
172
+ if info.isreg()
173
+ else "directory"
174
+ if info.isdir()
175
+ else "symlink"
176
+ if info.issym()
177
+ else "hardlink"
178
+ if info.islnk()
179
+ else "fifo"
180
+ if info.isfifo()
181
+ else "character-device"
182
+ if info.ischr()
183
+ else "block-device"
184
+ if info.isblk()
185
+ else "unknown"
186
+ ),
187
+ link_target=info.linkname if info.issym() or info.islnk() else None,
134
188
  raw=info,
135
189
  )
136
190
 
137
191
  @classmethod
138
192
  def from_rarinfo(cls, info: "rarfile.RarInfo") -> "ArchiveMemberInfo":
193
+ assert rarfile is not None
139
194
  if info.mtime is not None:
140
195
  mtime = info.mtime.timestamp()
141
196
  elif info.date_time is not None:
@@ -145,6 +200,29 @@ class ArchiveMemberInfo:
145
200
  assert info.filename is not None
146
201
  assert info.file_size is not None
147
202
  assert info.compress_size is not None
203
+ redir = info.file_redir
204
+ if redir is not None:
205
+ kind = cast(
206
+ ArchiveMemberKind,
207
+ {
208
+ rarfile.RAR5_XREDIR_UNIX_SYMLINK: "symlink",
209
+ rarfile.RAR5_XREDIR_WINDOWS_SYMLINK: "symlink",
210
+ rarfile.RAR5_XREDIR_WINDOWS_JUNCTION: "junction",
211
+ rarfile.RAR5_XREDIR_HARD_LINK: "hardlink",
212
+ rarfile.RAR5_XREDIR_FILE_COPY: "file",
213
+ }.get(redir[0], "unknown"),
214
+ )
215
+ link_target = redir[2]
216
+ else:
217
+ kind = (
218
+ "directory"
219
+ if info.is_dir()
220
+ else "symlink"
221
+ if info.is_symlink()
222
+ else _kind_from_mode(info.mode)
223
+ or ("file" if info.is_file() else "unknown")
224
+ )
225
+ link_target = None
148
226
  return cls(
149
227
  name=info.filename,
150
228
  uncompressed_size=info.file_size,
@@ -152,6 +230,8 @@ class ArchiveMemberInfo:
152
230
  mtime=mtime,
153
231
  mode=info.mode,
154
232
  is_dir=info.is_dir(),
233
+ kind=kind,
234
+ link_target=link_target,
155
235
  raw=info,
156
236
  )
157
237
 
@@ -557,6 +637,8 @@ class Archive:
557
637
  mtime=stat.st_mtime,
558
638
  mode=stat.st_mode & 0o777,
559
639
  is_dir=False,
640
+ kind="file",
641
+ link_target=None,
560
642
  raw=None,
561
643
  )
562
644
  ]