py7zz 0.1.0__py3-none-win_amd64.whl
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.
- py7zz/__init__.py +205 -0
- py7zz/async_ops.py +323 -0
- py7zz/bin/7z.dll +0 -0
- py7zz/bin/7zz.exe +0 -0
- py7zz/bundled_info.py +122 -0
- py7zz/cli.py +90 -0
- py7zz/compression.py +128 -0
- py7zz/config.py +260 -0
- py7zz/core.py +411 -0
- py7zz/exceptions.py +141 -0
- py7zz/simple.py +357 -0
- py7zz/updater.py +294 -0
- py7zz/version.py +267 -0
- py7zz-0.1.0.dist-info/METADATA +409 -0
- py7zz-0.1.0.dist-info/RECORD +20 -0
- py7zz-0.1.0.dist-info/WHEEL +4 -0
- py7zz-0.1.0.dist-info/entry_points.txt +2 -0
- py7zz-0.1.0.dist-info/licenses/LICENSE +52 -0
py7zz/__init__.py
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""
|
|
2
|
+
py7zz - Python wrapper for 7zz CLI tool
|
|
3
|
+
|
|
4
|
+
Provides a consistent OOP interface across platforms (macOS, Linux, Windows)
|
|
5
|
+
with automatic update mechanisms.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Configuration and Presets
|
|
9
|
+
# Bundled information
|
|
10
|
+
from .bundled_info import (
|
|
11
|
+
get_bundled_7zz_version,
|
|
12
|
+
get_release_type,
|
|
13
|
+
get_version_info,
|
|
14
|
+
is_auto_release,
|
|
15
|
+
is_dev_release,
|
|
16
|
+
is_stable_release,
|
|
17
|
+
)
|
|
18
|
+
from .config import Config, Presets, create_custom_config, get_recommended_preset
|
|
19
|
+
from .core import SevenZipFile, run_7z
|
|
20
|
+
|
|
21
|
+
# Exceptions
|
|
22
|
+
from .exceptions import (
|
|
23
|
+
ArchiveNotFoundError,
|
|
24
|
+
BinaryNotFoundError,
|
|
25
|
+
CompressionError,
|
|
26
|
+
ConfigurationError,
|
|
27
|
+
CorruptedArchiveError,
|
|
28
|
+
ExtractionError,
|
|
29
|
+
FileNotFoundError,
|
|
30
|
+
InsufficientSpaceError,
|
|
31
|
+
InvalidPasswordError,
|
|
32
|
+
OperationTimeoutError,
|
|
33
|
+
PasswordRequiredError,
|
|
34
|
+
Py7zzError,
|
|
35
|
+
UnsupportedFormatError,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Layer 1: Simple Function API
|
|
39
|
+
from .simple import (
|
|
40
|
+
compress_directory,
|
|
41
|
+
compress_file,
|
|
42
|
+
create_archive,
|
|
43
|
+
extract_archive,
|
|
44
|
+
get_archive_info,
|
|
45
|
+
list_archive,
|
|
46
|
+
test_archive,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Version information
|
|
50
|
+
from .version import (
|
|
51
|
+
generate_auto_version,
|
|
52
|
+
generate_dev_version,
|
|
53
|
+
get_base_version,
|
|
54
|
+
get_build_number,
|
|
55
|
+
get_version,
|
|
56
|
+
get_version_type,
|
|
57
|
+
is_auto_version,
|
|
58
|
+
is_dev_version,
|
|
59
|
+
is_stable_version,
|
|
60
|
+
parse_version,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Try to get dynamic version, fallback to hardcoded if needed
|
|
64
|
+
try:
|
|
65
|
+
__version__ = get_version()
|
|
66
|
+
except Exception:
|
|
67
|
+
# Fallback to hardcoded version if dynamic version fails
|
|
68
|
+
from .version import __version__
|
|
69
|
+
from .version import (
|
|
70
|
+
get_version_info as get_legacy_version_info,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Import async simple functions if available
|
|
74
|
+
try:
|
|
75
|
+
from .simple import (
|
|
76
|
+
compress_directory_async, # noqa: F401
|
|
77
|
+
compress_file_async, # noqa: F401
|
|
78
|
+
create_archive_async, # noqa: F401
|
|
79
|
+
extract_archive_async, # noqa: F401
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
_simple_async_available = True
|
|
83
|
+
except ImportError:
|
|
84
|
+
_simple_async_available = False
|
|
85
|
+
|
|
86
|
+
# Optional compression algorithm interface
|
|
87
|
+
try:
|
|
88
|
+
from .compression import (
|
|
89
|
+
Compressor, # noqa: F401
|
|
90
|
+
Decompressor, # noqa: F401
|
|
91
|
+
bzip2_compress, # noqa: F401
|
|
92
|
+
bzip2_decompress, # noqa: F401
|
|
93
|
+
compress, # noqa: F401
|
|
94
|
+
decompress, # noqa: F401
|
|
95
|
+
lzma2_compress, # noqa: F401
|
|
96
|
+
lzma2_decompress, # noqa: F401
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
_compression_available = True
|
|
100
|
+
except ImportError:
|
|
101
|
+
_compression_available = False
|
|
102
|
+
|
|
103
|
+
# Optional async operations interface
|
|
104
|
+
try:
|
|
105
|
+
from .async_ops import (
|
|
106
|
+
AsyncSevenZipFile, # noqa: F401
|
|
107
|
+
ProgressInfo, # noqa: F401
|
|
108
|
+
batch_compress_async, # noqa: F401
|
|
109
|
+
batch_extract_async, # noqa: F401
|
|
110
|
+
compress_async, # noqa: F401
|
|
111
|
+
extract_async, # noqa: F401
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
_async_available = True
|
|
115
|
+
except ImportError:
|
|
116
|
+
_async_available = False
|
|
117
|
+
|
|
118
|
+
# Build __all__ list based on available modules
|
|
119
|
+
__all__ = [
|
|
120
|
+
# Core API (Layer 2)
|
|
121
|
+
"SevenZipFile",
|
|
122
|
+
"run_7z",
|
|
123
|
+
# Version information
|
|
124
|
+
"__version__",
|
|
125
|
+
"get_version",
|
|
126
|
+
"get_version_info",
|
|
127
|
+
"get_legacy_version_info",
|
|
128
|
+
"parse_version",
|
|
129
|
+
"generate_auto_version",
|
|
130
|
+
"generate_dev_version",
|
|
131
|
+
"get_version_type",
|
|
132
|
+
"is_auto_version",
|
|
133
|
+
"is_dev_version",
|
|
134
|
+
"is_stable_version",
|
|
135
|
+
"get_base_version",
|
|
136
|
+
"get_build_number",
|
|
137
|
+
# Bundled information
|
|
138
|
+
"get_bundled_7zz_version",
|
|
139
|
+
"get_release_type",
|
|
140
|
+
"is_stable_release",
|
|
141
|
+
"is_auto_release",
|
|
142
|
+
"is_dev_release",
|
|
143
|
+
# Simple API (Layer 1)
|
|
144
|
+
"create_archive",
|
|
145
|
+
"extract_archive",
|
|
146
|
+
"list_archive",
|
|
147
|
+
"compress_file",
|
|
148
|
+
"compress_directory",
|
|
149
|
+
"get_archive_info",
|
|
150
|
+
"test_archive",
|
|
151
|
+
# Configuration
|
|
152
|
+
"Config",
|
|
153
|
+
"Presets",
|
|
154
|
+
"create_custom_config",
|
|
155
|
+
"get_recommended_preset",
|
|
156
|
+
# Exceptions
|
|
157
|
+
"Py7zzError",
|
|
158
|
+
"FileNotFoundError",
|
|
159
|
+
"ArchiveNotFoundError",
|
|
160
|
+
"CompressionError",
|
|
161
|
+
"ExtractionError",
|
|
162
|
+
"CorruptedArchiveError",
|
|
163
|
+
"UnsupportedFormatError",
|
|
164
|
+
"PasswordRequiredError",
|
|
165
|
+
"InvalidPasswordError",
|
|
166
|
+
"BinaryNotFoundError",
|
|
167
|
+
"InsufficientSpaceError",
|
|
168
|
+
"ConfigurationError",
|
|
169
|
+
"OperationTimeoutError",
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
# Add compression API if available
|
|
173
|
+
if _compression_available:
|
|
174
|
+
__all__.extend(
|
|
175
|
+
[
|
|
176
|
+
"compress",
|
|
177
|
+
"decompress",
|
|
178
|
+
"Compressor",
|
|
179
|
+
"Decompressor",
|
|
180
|
+
"lzma2_compress",
|
|
181
|
+
"lzma2_decompress",
|
|
182
|
+
"bzip2_compress",
|
|
183
|
+
"bzip2_decompress",
|
|
184
|
+
]
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Add async API if available
|
|
188
|
+
if _async_available:
|
|
189
|
+
__all__.extend(
|
|
190
|
+
[
|
|
191
|
+
"AsyncSevenZipFile",
|
|
192
|
+
"ProgressInfo",
|
|
193
|
+
"compress_async",
|
|
194
|
+
"extract_async",
|
|
195
|
+
"batch_compress_async",
|
|
196
|
+
"batch_extract_async",
|
|
197
|
+
]
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Add async simple API if available
|
|
201
|
+
if _simple_async_available:
|
|
202
|
+
__all__.extend(["create_archive_async", "extract_archive_async", "compress_file_async", "compress_directory_async"])
|
|
203
|
+
|
|
204
|
+
# Version is now managed centrally in version.py
|
|
205
|
+
# __version__ is imported from .version at the top of this file
|
py7zz/async_ops.py
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Asynchronous operations for py7zz package.
|
|
3
|
+
|
|
4
|
+
Provides async support for compression and extraction operations with progress reporting.
|
|
5
|
+
This module implements M4 milestone features for py7zz.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import subprocess
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Callable, List, Optional, Union
|
|
12
|
+
|
|
13
|
+
from .core import find_7z_binary
|
|
14
|
+
from .exceptions import FileNotFoundError
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ProgressInfo:
|
|
18
|
+
"""Progress information for async operations."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
operation: str,
|
|
23
|
+
current_file: str = "",
|
|
24
|
+
files_processed: int = 0,
|
|
25
|
+
total_files: int = 0,
|
|
26
|
+
bytes_processed: int = 0,
|
|
27
|
+
total_bytes: int = 0,
|
|
28
|
+
percentage: float = 0.0,
|
|
29
|
+
) -> None:
|
|
30
|
+
self.operation = operation
|
|
31
|
+
self.current_file = current_file
|
|
32
|
+
self.files_processed = files_processed
|
|
33
|
+
self.total_files = total_files
|
|
34
|
+
self.bytes_processed = bytes_processed
|
|
35
|
+
self.total_bytes = total_bytes
|
|
36
|
+
self.percentage = percentage
|
|
37
|
+
|
|
38
|
+
def __repr__(self) -> str:
|
|
39
|
+
return (
|
|
40
|
+
f"ProgressInfo(operation='{self.operation}', "
|
|
41
|
+
f"current_file='{self.current_file}', "
|
|
42
|
+
f"files_processed={self.files_processed}, "
|
|
43
|
+
f"total_files={self.total_files}, "
|
|
44
|
+
f"percentage={self.percentage:.1f}%)"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class AsyncSevenZipFile:
|
|
49
|
+
"""
|
|
50
|
+
Async wrapper for SevenZipFile operations.
|
|
51
|
+
|
|
52
|
+
Provides asynchronous compression and extraction with progress reporting.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, file: Union[str, Path], mode: str = "r"):
|
|
56
|
+
"""
|
|
57
|
+
Initialize AsyncSevenZipFile.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
file: Path to the archive file
|
|
61
|
+
mode: File mode ('r' for read, 'w' for write)
|
|
62
|
+
"""
|
|
63
|
+
self.file = Path(file)
|
|
64
|
+
self.mode = mode
|
|
65
|
+
self._validate_mode()
|
|
66
|
+
|
|
67
|
+
def _validate_mode(self) -> None:
|
|
68
|
+
"""Validate file mode."""
|
|
69
|
+
if self.mode not in ("r", "w"):
|
|
70
|
+
raise ValueError(f"Invalid mode: {self.mode}")
|
|
71
|
+
|
|
72
|
+
async def __aenter__(self) -> "AsyncSevenZipFile":
|
|
73
|
+
"""Async context manager entry."""
|
|
74
|
+
return self
|
|
75
|
+
|
|
76
|
+
async def __aexit__(
|
|
77
|
+
self, exc_type: Optional[type], exc_val: Optional[BaseException], exc_tb: Optional[object]
|
|
78
|
+
) -> None:
|
|
79
|
+
"""Async context manager exit."""
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
async def add_async(
|
|
83
|
+
self, name: Union[str, Path], progress_callback: Optional[Callable[[ProgressInfo], None]] = None
|
|
84
|
+
) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Add file or directory to archive asynchronously.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
name: Path to file or directory to add
|
|
90
|
+
progress_callback: Optional callback for progress updates
|
|
91
|
+
"""
|
|
92
|
+
if self.mode == "r":
|
|
93
|
+
raise ValueError("Cannot add to archive opened in read mode")
|
|
94
|
+
|
|
95
|
+
name = Path(name)
|
|
96
|
+
if not name.exists():
|
|
97
|
+
raise FileNotFoundError(f"File not found: {name}")
|
|
98
|
+
|
|
99
|
+
# Build 7z command
|
|
100
|
+
binary = find_7z_binary()
|
|
101
|
+
args = [binary, "a", str(self.file), str(name)]
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
await self._run_with_progress(args, operation="compress", progress_callback=progress_callback)
|
|
105
|
+
except subprocess.CalledProcessError as e:
|
|
106
|
+
raise RuntimeError(f"Failed to add {name} to archive: {e.stderr}") from e
|
|
107
|
+
|
|
108
|
+
async def extract_async(
|
|
109
|
+
self,
|
|
110
|
+
path: Union[str, Path] = ".",
|
|
111
|
+
overwrite: bool = False,
|
|
112
|
+
progress_callback: Optional[Callable[[ProgressInfo], None]] = None,
|
|
113
|
+
) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Extract archive contents asynchronously.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
path: Directory to extract to
|
|
119
|
+
overwrite: Whether to overwrite existing files
|
|
120
|
+
progress_callback: Optional callback for progress updates
|
|
121
|
+
"""
|
|
122
|
+
if self.mode == "w":
|
|
123
|
+
raise ValueError("Cannot extract from archive opened in write mode")
|
|
124
|
+
|
|
125
|
+
if not self.file.exists():
|
|
126
|
+
raise FileNotFoundError(f"Archive not found: {self.file}")
|
|
127
|
+
|
|
128
|
+
path = Path(path)
|
|
129
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
130
|
+
|
|
131
|
+
binary = find_7z_binary()
|
|
132
|
+
args = [binary, "x", str(self.file), f"-o{path}"]
|
|
133
|
+
|
|
134
|
+
if overwrite:
|
|
135
|
+
args.append("-y")
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
await self._run_with_progress(args, operation="extract", progress_callback=progress_callback)
|
|
139
|
+
except subprocess.CalledProcessError as e:
|
|
140
|
+
raise RuntimeError(f"Failed to extract archive: {e.stderr}") from e
|
|
141
|
+
|
|
142
|
+
async def _run_with_progress(
|
|
143
|
+
self, args: List[str], operation: str, progress_callback: Optional[Callable[[ProgressInfo], None]] = None
|
|
144
|
+
) -> None:
|
|
145
|
+
"""
|
|
146
|
+
Run 7z command with progress monitoring.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
args: Command arguments
|
|
150
|
+
operation: Operation type ('compress' or 'extract')
|
|
151
|
+
progress_callback: Optional callback for progress updates
|
|
152
|
+
"""
|
|
153
|
+
process = await asyncio.create_subprocess_exec(
|
|
154
|
+
*args, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
if progress_callback:
|
|
159
|
+
# Monitor progress in separate task
|
|
160
|
+
progress_task = asyncio.create_task(self._monitor_progress(process, operation, progress_callback))
|
|
161
|
+
await progress_task
|
|
162
|
+
# Wait for process completion
|
|
163
|
+
await process.wait()
|
|
164
|
+
stdout, stderr = b"", b""
|
|
165
|
+
else:
|
|
166
|
+
stdout, stderr = await process.communicate()
|
|
167
|
+
|
|
168
|
+
if process.returncode != 0:
|
|
169
|
+
raise subprocess.CalledProcessError(process.returncode or -1, args, stdout, stderr)
|
|
170
|
+
|
|
171
|
+
except asyncio.CancelledError:
|
|
172
|
+
if process.returncode is None:
|
|
173
|
+
process.terminate()
|
|
174
|
+
await process.wait()
|
|
175
|
+
raise
|
|
176
|
+
|
|
177
|
+
async def _monitor_progress(
|
|
178
|
+
self, process: asyncio.subprocess.Process, operation: str, progress_callback: Callable[[ProgressInfo], None]
|
|
179
|
+
) -> None:
|
|
180
|
+
"""
|
|
181
|
+
Monitor subprocess progress and call callback.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
process: Subprocess to monitor
|
|
185
|
+
operation: Operation type
|
|
186
|
+
progress_callback: Callback for progress updates
|
|
187
|
+
"""
|
|
188
|
+
files_processed = 0
|
|
189
|
+
current_file = ""
|
|
190
|
+
|
|
191
|
+
if process.stdout is None:
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
async for line_bytes in process.stdout:
|
|
195
|
+
line = line_bytes.decode("utf-8", errors="replace").strip()
|
|
196
|
+
|
|
197
|
+
# Parse 7z output for progress information
|
|
198
|
+
if "Compressing" in line or "Extracting" in line:
|
|
199
|
+
# Extract filename from progress line
|
|
200
|
+
if " " in line:
|
|
201
|
+
current_file = line.split(" ")[-1]
|
|
202
|
+
files_processed += 1
|
|
203
|
+
|
|
204
|
+
# Calculate approximate progress
|
|
205
|
+
# Note: This is simplified - actual 7z progress parsing is more complex
|
|
206
|
+
progress = ProgressInfo(
|
|
207
|
+
operation=operation,
|
|
208
|
+
current_file=current_file,
|
|
209
|
+
files_processed=files_processed,
|
|
210
|
+
total_files=max(1, files_processed), # Placeholder
|
|
211
|
+
percentage=min(100.0, files_processed * 10.0), # Simplified calculation
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
progress_callback(progress)
|
|
215
|
+
|
|
216
|
+
# Small delay to prevent callback spam
|
|
217
|
+
await asyncio.sleep(0.01)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
async def compress_async(
|
|
221
|
+
archive_path: Union[str, Path],
|
|
222
|
+
files: List[Union[str, Path]],
|
|
223
|
+
progress_callback: Optional[Callable[[ProgressInfo], None]] = None,
|
|
224
|
+
) -> None:
|
|
225
|
+
"""
|
|
226
|
+
Compress files asynchronously with progress reporting.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
archive_path: Path to the archive to create
|
|
230
|
+
files: List of files/directories to add
|
|
231
|
+
progress_callback: Optional callback for progress updates
|
|
232
|
+
|
|
233
|
+
Example:
|
|
234
|
+
>>> async def progress_handler(info):
|
|
235
|
+
... print(f"Progress: {info.percentage:.1f}% - {info.current_file}")
|
|
236
|
+
>>> await py7zz.compress_async("backup.7z", ["documents/"], progress_handler)
|
|
237
|
+
"""
|
|
238
|
+
async with AsyncSevenZipFile(archive_path, "w") as sz:
|
|
239
|
+
for file_path in files:
|
|
240
|
+
path = Path(file_path)
|
|
241
|
+
if path.exists():
|
|
242
|
+
await sz.add_async(file_path, progress_callback)
|
|
243
|
+
else:
|
|
244
|
+
raise FileNotFoundError(f"File or directory not found: {file_path}")
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
async def extract_async(
|
|
248
|
+
archive_path: Union[str, Path],
|
|
249
|
+
output_dir: Union[str, Path] = ".",
|
|
250
|
+
overwrite: bool = True,
|
|
251
|
+
progress_callback: Optional[Callable[[ProgressInfo], None]] = None,
|
|
252
|
+
) -> None:
|
|
253
|
+
"""
|
|
254
|
+
Extract archive asynchronously with progress reporting.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
archive_path: Path to the archive to extract
|
|
258
|
+
output_dir: Directory to extract files to
|
|
259
|
+
overwrite: Whether to overwrite existing files
|
|
260
|
+
progress_callback: Optional callback for progress updates
|
|
261
|
+
|
|
262
|
+
Example:
|
|
263
|
+
>>> async def progress_handler(info):
|
|
264
|
+
... print(f"Extracting: {info.current_file}")
|
|
265
|
+
>>> await py7zz.extract_async("backup.7z", "extracted/", progress_handler)
|
|
266
|
+
"""
|
|
267
|
+
if not Path(archive_path).exists():
|
|
268
|
+
raise FileNotFoundError(f"Archive not found: {archive_path}")
|
|
269
|
+
|
|
270
|
+
async with AsyncSevenZipFile(archive_path, "r") as sz:
|
|
271
|
+
await sz.extract_async(output_dir, overwrite, progress_callback)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
async def batch_compress_async(
|
|
275
|
+
operations: List[tuple], progress_callback: Optional[Callable[[ProgressInfo], None]] = None
|
|
276
|
+
) -> None:
|
|
277
|
+
"""
|
|
278
|
+
Perform multiple compression operations concurrently.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
operations: List of (archive_path, files) tuples
|
|
282
|
+
progress_callback: Optional callback for progress updates
|
|
283
|
+
|
|
284
|
+
Example:
|
|
285
|
+
>>> operations = [
|
|
286
|
+
... ("backup1.7z", ["documents/"]),
|
|
287
|
+
... ("backup2.7z", ["photos/"]),
|
|
288
|
+
... ]
|
|
289
|
+
>>> await py7zz.batch_compress_async(operations)
|
|
290
|
+
"""
|
|
291
|
+
tasks = []
|
|
292
|
+
|
|
293
|
+
for archive_path, files in operations:
|
|
294
|
+
task = compress_async(archive_path, files, progress_callback)
|
|
295
|
+
tasks.append(task)
|
|
296
|
+
|
|
297
|
+
await asyncio.gather(*tasks)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
async def batch_extract_async(
|
|
301
|
+
operations: List[tuple], progress_callback: Optional[Callable[[ProgressInfo], None]] = None
|
|
302
|
+
) -> None:
|
|
303
|
+
"""
|
|
304
|
+
Perform multiple extraction operations concurrently.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
operations: List of (archive_path, output_dir) tuples
|
|
308
|
+
progress_callback: Optional callback for progress updates
|
|
309
|
+
|
|
310
|
+
Example:
|
|
311
|
+
>>> operations = [
|
|
312
|
+
... ("backup1.7z", "extracted1/"),
|
|
313
|
+
... ("backup2.7z", "extracted2/"),
|
|
314
|
+
... ]
|
|
315
|
+
>>> await py7zz.batch_extract_async(operations)
|
|
316
|
+
"""
|
|
317
|
+
tasks = []
|
|
318
|
+
|
|
319
|
+
for archive_path, output_dir in operations:
|
|
320
|
+
task = extract_async(archive_path, output_dir, progress_callback=progress_callback)
|
|
321
|
+
tasks.append(task)
|
|
322
|
+
|
|
323
|
+
await asyncio.gather(*tasks)
|
py7zz/bin/7z.dll
ADDED
|
Binary file
|
py7zz/bin/7zz.exe
ADDED
|
Binary file
|
py7zz/bundled_info.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Bundled version information for py7zz package.
|
|
3
|
+
|
|
4
|
+
This module provides version registry and bundled information for the py7zz package,
|
|
5
|
+
supporting the new PEP 440 compliant version system.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, Union
|
|
9
|
+
|
|
10
|
+
from .version import __version__
|
|
11
|
+
|
|
12
|
+
# Version registry containing all version information
|
|
13
|
+
VERSION_REGISTRY: Dict[str, Dict[str, Union[str, None]]] = {
|
|
14
|
+
"0.1.0": {
|
|
15
|
+
"7zz_version": "25.00",
|
|
16
|
+
"release_date": "2024-12-15",
|
|
17
|
+
"release_type": "stable",
|
|
18
|
+
"github_tag": "v0.1.0",
|
|
19
|
+
"changelog_url": "https://github.com/rxchi1d/py7zz/releases/tag/v0.1.0",
|
|
20
|
+
},
|
|
21
|
+
# Auto versions will be dynamically added by CI/CD
|
|
22
|
+
# Example: "0.1.0a1": {"7zz_version": "24.08", ...}
|
|
23
|
+
# Dev versions will be manually added
|
|
24
|
+
# Example: "0.2.0.dev1": {"7zz_version": "24.08", ...}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_version_info() -> Dict[str, Union[str, None]]:
|
|
29
|
+
"""
|
|
30
|
+
Get detailed version information for the current py7zz version.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Dictionary containing version information including:
|
|
34
|
+
- py7zz_version: Current py7zz version
|
|
35
|
+
- bundled_7zz_version: Bundled 7zz version
|
|
36
|
+
- release_type: Type of release (stable, auto, dev)
|
|
37
|
+
- release_date: Release date
|
|
38
|
+
- github_tag: GitHub tag
|
|
39
|
+
- changelog_url: URL to changelog
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
>>> get_version_info()
|
|
43
|
+
{
|
|
44
|
+
'py7zz_version': '0.1.0',
|
|
45
|
+
'bundled_7zz_version': '24.07',
|
|
46
|
+
'release_type': 'stable',
|
|
47
|
+
'release_date': '2024-12-15',
|
|
48
|
+
'github_tag': 'v0.1.0',
|
|
49
|
+
'changelog_url': 'https://github.com/rxchi1d/py7zz/releases/tag/v0.1.0'
|
|
50
|
+
}
|
|
51
|
+
"""
|
|
52
|
+
current_version = __version__
|
|
53
|
+
info = VERSION_REGISTRY.get(current_version, {})
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
"py7zz_version": current_version,
|
|
57
|
+
"bundled_7zz_version": info.get("7zz_version", "unknown"),
|
|
58
|
+
"release_type": info.get("release_type", "unknown"),
|
|
59
|
+
"release_date": info.get("release_date", "unknown"),
|
|
60
|
+
"github_tag": info.get("github_tag", f"v{current_version}"),
|
|
61
|
+
"changelog_url": info.get("changelog_url", f"https://github.com/rxchi1d/py7zz/releases/tag/v{current_version}"),
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_bundled_7zz_version() -> str:
|
|
66
|
+
"""
|
|
67
|
+
Get the bundled 7zz version for the current py7zz version.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
Bundled 7zz version string
|
|
71
|
+
|
|
72
|
+
Example:
|
|
73
|
+
>>> get_bundled_7zz_version()
|
|
74
|
+
'24.07'
|
|
75
|
+
"""
|
|
76
|
+
version = get_version_info()["bundled_7zz_version"]
|
|
77
|
+
return version if isinstance(version, str) else "unknown"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_release_type() -> str:
|
|
81
|
+
"""
|
|
82
|
+
Get the release type for the current py7zz version.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Release type: 'stable', 'auto', or 'dev'
|
|
86
|
+
|
|
87
|
+
Example:
|
|
88
|
+
>>> get_release_type()
|
|
89
|
+
'stable'
|
|
90
|
+
"""
|
|
91
|
+
release_type = get_version_info()["release_type"]
|
|
92
|
+
return release_type if isinstance(release_type, str) else "unknown"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def is_stable_release() -> bool:
|
|
96
|
+
"""
|
|
97
|
+
Check if the current version is a stable release.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
True if current version is stable
|
|
101
|
+
"""
|
|
102
|
+
return get_release_type() == "stable"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def is_auto_release() -> bool:
|
|
106
|
+
"""
|
|
107
|
+
Check if the current version is an auto release.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
True if current version is auto
|
|
111
|
+
"""
|
|
112
|
+
return get_release_type() == "auto"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def is_dev_release() -> bool:
|
|
116
|
+
"""
|
|
117
|
+
Check if the current version is a dev release.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
True if current version is dev
|
|
121
|
+
"""
|
|
122
|
+
return get_release_type() == "dev"
|