splitzip 0.1.0__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.
- splitzip-0.1.0/.gitignore +10 -0
- splitzip-0.1.0/LICENSE +21 -0
- splitzip-0.1.0/PKG-INFO +228 -0
- splitzip-0.1.0/README.md +197 -0
- splitzip-0.1.0/pyproject.toml +63 -0
- splitzip-0.1.0/src/splitzip/__init__.py +107 -0
- splitzip-0.1.0/src/splitzip/__main__.py +153 -0
- splitzip-0.1.0/src/splitzip/exceptions.py +45 -0
- splitzip-0.1.0/src/splitzip/structures.py +386 -0
- splitzip-0.1.0/src/splitzip/utils.py +183 -0
- splitzip-0.1.0/src/splitzip/volume.py +268 -0
- splitzip-0.1.0/src/splitzip/writer.py +554 -0
- splitzip-0.1.0/tests/__init__.py +1 -0
- splitzip-0.1.0/tests/test_structures.py +154 -0
- splitzip-0.1.0/tests/test_utils.py +118 -0
- splitzip-0.1.0/tests/test_writer.py +326 -0
splitzip-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jimothy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
splitzip-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: splitzip
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Create split ZIP archives compatible with standard tools
|
|
5
|
+
Project-URL: Homepage, https://github.com/twwat/splitzip
|
|
6
|
+
Project-URL: Repository, https://github.com/twwat/splitzip
|
|
7
|
+
Project-URL: Issues, https://github.com/twwat/splitzip/issues
|
|
8
|
+
Author-email: twwat <mailto.yourusername@wwwcomdot.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: 7z,archive,compression,multipart,split,zip
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: System :: Archiving :: Compression
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
[](https://pypi.org/project/splitzip/) [](https://pypi.org/project/splitzip/) [](https://opensource.org/licenses/MIT)
|
|
33
|
+
|
|
34
|
+
# splitzip
|
|
35
|
+
|
|
36
|
+
Create split ZIP archives compatible with standard tools.
|
|
37
|
+
|
|
38
|
+
**No 7-Zip required.** Archives created with splitzip can be extracted using Windows Explorer, WinZip, macOS Archive Utility, and standard `unzip` on Linux.
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- Pure Python, no external dependencies
|
|
43
|
+
- Compatible with standard ZIP tools (no proprietary formats)
|
|
44
|
+
- Human-friendly size specifications (`"100MB"`, `"700MiB"`, `"4.7GB"`)
|
|
45
|
+
- Progress callbacks for large files
|
|
46
|
+
- Context manager support
|
|
47
|
+
- CLI tool included
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install splitzip
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
### Simple Usage
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import splitzip
|
|
61
|
+
|
|
62
|
+
# Create a split archive from files
|
|
63
|
+
splitzip.create(
|
|
64
|
+
"backup.zip",
|
|
65
|
+
["documents/", "photos/", "important.pdf"],
|
|
66
|
+
split_size="650MB"
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Output files: `backup.z01`, `backup.z02`, ..., `backup.zip`
|
|
71
|
+
|
|
72
|
+
### Context Manager
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from splitzip import SplitZipWriter
|
|
76
|
+
|
|
77
|
+
with SplitZipWriter("backup.zip", split_size="100MB") as zf:
|
|
78
|
+
# Add files
|
|
79
|
+
zf.write("document.pdf")
|
|
80
|
+
zf.write("photos/", recursive=True)
|
|
81
|
+
|
|
82
|
+
# Add with custom name
|
|
83
|
+
zf.write("secret.txt", arcname="data/renamed.txt")
|
|
84
|
+
|
|
85
|
+
# Add content directly
|
|
86
|
+
zf.writestr("hello.txt", b"Hello, World!")
|
|
87
|
+
zf.writestr("config.json", '{"key": "value"}')
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Advanced Options
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from splitzip import SplitZipWriter, STORED, DEFLATED
|
|
94
|
+
|
|
95
|
+
def on_progress(filename, bytes_done, total_bytes):
|
|
96
|
+
pct = (bytes_done / total_bytes) * 100
|
|
97
|
+
print(f"\r{filename}: {pct:.1f}%", end="")
|
|
98
|
+
|
|
99
|
+
def on_volume(volume_num, path):
|
|
100
|
+
print(f"Created volume: {path}")
|
|
101
|
+
|
|
102
|
+
with SplitZipWriter(
|
|
103
|
+
"backup.zip",
|
|
104
|
+
split_size="700MiB", # DVD size
|
|
105
|
+
compression=DEFLATED, # or STORED for no compression
|
|
106
|
+
compresslevel=9, # 1-9 (default: 6)
|
|
107
|
+
on_volume=on_volume, # Volume creation callback
|
|
108
|
+
on_progress=on_progress, # Progress callback
|
|
109
|
+
) as zf:
|
|
110
|
+
zf.write("large_file.bin")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Streaming from File Objects
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
import io
|
|
117
|
+
from splitzip import SplitZipWriter
|
|
118
|
+
|
|
119
|
+
data = get_data_from_somewhere()
|
|
120
|
+
|
|
121
|
+
with SplitZipWriter("archive.zip", split_size="100MB") as zf:
|
|
122
|
+
zf.write_fileobj(
|
|
123
|
+
io.BytesIO(data),
|
|
124
|
+
arcname="streamed.bin",
|
|
125
|
+
size=len(data) # Optional, enables progress callback
|
|
126
|
+
)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Size Specifications
|
|
130
|
+
|
|
131
|
+
splitzip accepts sizes in multiple formats:
|
|
132
|
+
|
|
133
|
+
| Format | Example | Bytes |
|
|
134
|
+
|--------|---------|-------|
|
|
135
|
+
| Integer | `104857600` | 104,857,600 |
|
|
136
|
+
| Bytes | `"100B"` | 100 |
|
|
137
|
+
| Kilobytes (decimal) | `"100KB"` | 100,000 |
|
|
138
|
+
| Megabytes (decimal) | `"100MB"` | 100,000,000 |
|
|
139
|
+
| Gigabytes (decimal) | `"4.7GB"` | 4,700,000,000 |
|
|
140
|
+
| Kibibytes (binary) | `"100KiB"` | 102,400 |
|
|
141
|
+
| Mebibytes (binary) | `"700MiB"` | 734,003,200 |
|
|
142
|
+
| Gibibytes (binary) | `"1GiB"` | 1,073,741,824 |
|
|
143
|
+
|
|
144
|
+
Common split sizes:
|
|
145
|
+
- CD-ROM: `"650MB"` or `"700MB"`
|
|
146
|
+
- DVD: `"4.7GB"`
|
|
147
|
+
- FAT32 limit: `"4GiB"` (minus 1 byte)
|
|
148
|
+
- Email attachment: `"25MB"`
|
|
149
|
+
|
|
150
|
+
## Command Line Interface
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Create a split archive
|
|
154
|
+
splitzip create -o backup.zip -s 100MB file1.txt directory/
|
|
155
|
+
|
|
156
|
+
# With options
|
|
157
|
+
splitzip create -o backup.zip -s 700MiB \
|
|
158
|
+
--level 9 \ # Max compression
|
|
159
|
+
--verbose \ # Show progress
|
|
160
|
+
documents/ photos/
|
|
161
|
+
|
|
162
|
+
# Store without compression
|
|
163
|
+
splitzip create -o backup.zip -s 100MB --store largefile.bin
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Output File Naming
|
|
167
|
+
|
|
168
|
+
splitzip follows the standard ZIP split archive convention:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
backup.z01 (first volume)
|
|
172
|
+
backup.z02 (second volume)
|
|
173
|
+
backup.z03 (third volume)
|
|
174
|
+
...
|
|
175
|
+
backup.zip (final volume, contains central directory)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**All files must be present in the same directory for extraction.**
|
|
179
|
+
|
|
180
|
+
## Compatibility
|
|
181
|
+
|
|
182
|
+
| Tool | Single Volume | Split Archive |
|
|
183
|
+
|------|:-------------:|:-------------:|
|
|
184
|
+
| Windows Explorer | ✅ | ✅ |
|
|
185
|
+
| WinZip | ✅ | ✅ |
|
|
186
|
+
| 7-Zip | ✅ | ✅ |
|
|
187
|
+
| macOS Archive Utility | ✅ | ✅* |
|
|
188
|
+
| Linux `unzip` | ✅ | ✅** |
|
|
189
|
+
| Python `zipfile` | ✅ | ❌ |
|
|
190
|
+
|
|
191
|
+
\* May require all files to be selected and opened together
|
|
192
|
+
\*\* May require `unzip -F` flag for split archives
|
|
193
|
+
|
|
194
|
+
## Limitations
|
|
195
|
+
|
|
196
|
+
- **No ZIP64 support yet**: Individual files must be under 4GB, total entries under 65,535
|
|
197
|
+
- **No encryption**: Use filesystem encryption for sensitive data
|
|
198
|
+
- **No reading/extraction**: This is a write-only library (use standard tools to extract)
|
|
199
|
+
- **No ZSTD/LZMA**: Only DEFLATE and STORED compression (for compatibility)
|
|
200
|
+
|
|
201
|
+
## Development
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# Clone and install in development mode
|
|
205
|
+
git clone https://github.com/jimothy/splitzip
|
|
206
|
+
cd splitzip
|
|
207
|
+
pip install -e ".[dev]"
|
|
208
|
+
|
|
209
|
+
# Run tests
|
|
210
|
+
pytest
|
|
211
|
+
|
|
212
|
+
# Run with coverage
|
|
213
|
+
pytest --cov=splitzip
|
|
214
|
+
|
|
215
|
+
# Type checking
|
|
216
|
+
mypy src/splitzip
|
|
217
|
+
|
|
218
|
+
# Linting
|
|
219
|
+
ruff check src/splitzip
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
225
|
+
|
|
226
|
+
## Contributing
|
|
227
|
+
|
|
228
|
+
Contributions welcome! Please open an issue to discuss major changes before submitting a PR.
|
splitzip-0.1.0/README.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
[](https://pypi.org/project/splitzip/) [](https://pypi.org/project/splitzip/) [](https://opensource.org/licenses/MIT)
|
|
2
|
+
|
|
3
|
+
# splitzip
|
|
4
|
+
|
|
5
|
+
Create split ZIP archives compatible with standard tools.
|
|
6
|
+
|
|
7
|
+
**No 7-Zip required.** Archives created with splitzip can be extracted using Windows Explorer, WinZip, macOS Archive Utility, and standard `unzip` on Linux.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Pure Python, no external dependencies
|
|
12
|
+
- Compatible with standard ZIP tools (no proprietary formats)
|
|
13
|
+
- Human-friendly size specifications (`"100MB"`, `"700MiB"`, `"4.7GB"`)
|
|
14
|
+
- Progress callbacks for large files
|
|
15
|
+
- Context manager support
|
|
16
|
+
- CLI tool included
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install splitzip
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### Simple Usage
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import splitzip
|
|
30
|
+
|
|
31
|
+
# Create a split archive from files
|
|
32
|
+
splitzip.create(
|
|
33
|
+
"backup.zip",
|
|
34
|
+
["documents/", "photos/", "important.pdf"],
|
|
35
|
+
split_size="650MB"
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Output files: `backup.z01`, `backup.z02`, ..., `backup.zip`
|
|
40
|
+
|
|
41
|
+
### Context Manager
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from splitzip import SplitZipWriter
|
|
45
|
+
|
|
46
|
+
with SplitZipWriter("backup.zip", split_size="100MB") as zf:
|
|
47
|
+
# Add files
|
|
48
|
+
zf.write("document.pdf")
|
|
49
|
+
zf.write("photos/", recursive=True)
|
|
50
|
+
|
|
51
|
+
# Add with custom name
|
|
52
|
+
zf.write("secret.txt", arcname="data/renamed.txt")
|
|
53
|
+
|
|
54
|
+
# Add content directly
|
|
55
|
+
zf.writestr("hello.txt", b"Hello, World!")
|
|
56
|
+
zf.writestr("config.json", '{"key": "value"}')
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Advanced Options
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from splitzip import SplitZipWriter, STORED, DEFLATED
|
|
63
|
+
|
|
64
|
+
def on_progress(filename, bytes_done, total_bytes):
|
|
65
|
+
pct = (bytes_done / total_bytes) * 100
|
|
66
|
+
print(f"\r{filename}: {pct:.1f}%", end="")
|
|
67
|
+
|
|
68
|
+
def on_volume(volume_num, path):
|
|
69
|
+
print(f"Created volume: {path}")
|
|
70
|
+
|
|
71
|
+
with SplitZipWriter(
|
|
72
|
+
"backup.zip",
|
|
73
|
+
split_size="700MiB", # DVD size
|
|
74
|
+
compression=DEFLATED, # or STORED for no compression
|
|
75
|
+
compresslevel=9, # 1-9 (default: 6)
|
|
76
|
+
on_volume=on_volume, # Volume creation callback
|
|
77
|
+
on_progress=on_progress, # Progress callback
|
|
78
|
+
) as zf:
|
|
79
|
+
zf.write("large_file.bin")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Streaming from File Objects
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import io
|
|
86
|
+
from splitzip import SplitZipWriter
|
|
87
|
+
|
|
88
|
+
data = get_data_from_somewhere()
|
|
89
|
+
|
|
90
|
+
with SplitZipWriter("archive.zip", split_size="100MB") as zf:
|
|
91
|
+
zf.write_fileobj(
|
|
92
|
+
io.BytesIO(data),
|
|
93
|
+
arcname="streamed.bin",
|
|
94
|
+
size=len(data) # Optional, enables progress callback
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Size Specifications
|
|
99
|
+
|
|
100
|
+
splitzip accepts sizes in multiple formats:
|
|
101
|
+
|
|
102
|
+
| Format | Example | Bytes |
|
|
103
|
+
|--------|---------|-------|
|
|
104
|
+
| Integer | `104857600` | 104,857,600 |
|
|
105
|
+
| Bytes | `"100B"` | 100 |
|
|
106
|
+
| Kilobytes (decimal) | `"100KB"` | 100,000 |
|
|
107
|
+
| Megabytes (decimal) | `"100MB"` | 100,000,000 |
|
|
108
|
+
| Gigabytes (decimal) | `"4.7GB"` | 4,700,000,000 |
|
|
109
|
+
| Kibibytes (binary) | `"100KiB"` | 102,400 |
|
|
110
|
+
| Mebibytes (binary) | `"700MiB"` | 734,003,200 |
|
|
111
|
+
| Gibibytes (binary) | `"1GiB"` | 1,073,741,824 |
|
|
112
|
+
|
|
113
|
+
Common split sizes:
|
|
114
|
+
- CD-ROM: `"650MB"` or `"700MB"`
|
|
115
|
+
- DVD: `"4.7GB"`
|
|
116
|
+
- FAT32 limit: `"4GiB"` (minus 1 byte)
|
|
117
|
+
- Email attachment: `"25MB"`
|
|
118
|
+
|
|
119
|
+
## Command Line Interface
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Create a split archive
|
|
123
|
+
splitzip create -o backup.zip -s 100MB file1.txt directory/
|
|
124
|
+
|
|
125
|
+
# With options
|
|
126
|
+
splitzip create -o backup.zip -s 700MiB \
|
|
127
|
+
--level 9 \ # Max compression
|
|
128
|
+
--verbose \ # Show progress
|
|
129
|
+
documents/ photos/
|
|
130
|
+
|
|
131
|
+
# Store without compression
|
|
132
|
+
splitzip create -o backup.zip -s 100MB --store largefile.bin
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Output File Naming
|
|
136
|
+
|
|
137
|
+
splitzip follows the standard ZIP split archive convention:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
backup.z01 (first volume)
|
|
141
|
+
backup.z02 (second volume)
|
|
142
|
+
backup.z03 (third volume)
|
|
143
|
+
...
|
|
144
|
+
backup.zip (final volume, contains central directory)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**All files must be present in the same directory for extraction.**
|
|
148
|
+
|
|
149
|
+
## Compatibility
|
|
150
|
+
|
|
151
|
+
| Tool | Single Volume | Split Archive |
|
|
152
|
+
|------|:-------------:|:-------------:|
|
|
153
|
+
| Windows Explorer | ✅ | ✅ |
|
|
154
|
+
| WinZip | ✅ | ✅ |
|
|
155
|
+
| 7-Zip | ✅ | ✅ |
|
|
156
|
+
| macOS Archive Utility | ✅ | ✅* |
|
|
157
|
+
| Linux `unzip` | ✅ | ✅** |
|
|
158
|
+
| Python `zipfile` | ✅ | ❌ |
|
|
159
|
+
|
|
160
|
+
\* May require all files to be selected and opened together
|
|
161
|
+
\*\* May require `unzip -F` flag for split archives
|
|
162
|
+
|
|
163
|
+
## Limitations
|
|
164
|
+
|
|
165
|
+
- **No ZIP64 support yet**: Individual files must be under 4GB, total entries under 65,535
|
|
166
|
+
- **No encryption**: Use filesystem encryption for sensitive data
|
|
167
|
+
- **No reading/extraction**: This is a write-only library (use standard tools to extract)
|
|
168
|
+
- **No ZSTD/LZMA**: Only DEFLATE and STORED compression (for compatibility)
|
|
169
|
+
|
|
170
|
+
## Development
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# Clone and install in development mode
|
|
174
|
+
git clone https://github.com/jimothy/splitzip
|
|
175
|
+
cd splitzip
|
|
176
|
+
pip install -e ".[dev]"
|
|
177
|
+
|
|
178
|
+
# Run tests
|
|
179
|
+
pytest
|
|
180
|
+
|
|
181
|
+
# Run with coverage
|
|
182
|
+
pytest --cov=splitzip
|
|
183
|
+
|
|
184
|
+
# Type checking
|
|
185
|
+
mypy src/splitzip
|
|
186
|
+
|
|
187
|
+
# Linting
|
|
188
|
+
ruff check src/splitzip
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
194
|
+
|
|
195
|
+
## Contributing
|
|
196
|
+
|
|
197
|
+
Contributions welcome! Please open an issue to discuss major changes before submitting a PR.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "splitzip"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Create split ZIP archives compatible with standard tools"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "twwat", email = "mailto.yourusername@wwwcomdot.com" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["zip", "archive", "split", "multipart", "compression", "7z"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Programming Language :: Python :: 3.14",
|
|
28
|
+
"Topic :: System :: Archiving :: Compression",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/twwat/splitzip"
|
|
33
|
+
Repository = "https://github.com/twwat/splitzip"
|
|
34
|
+
Issues = "https://github.com/twwat/splitzip/issues"
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=7.0",
|
|
39
|
+
"pytest-cov>=4.0",
|
|
40
|
+
"ruff>=0.1.0",
|
|
41
|
+
"mypy>=1.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
splitzip = "splitzip.__main__:main"
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.wheel]
|
|
48
|
+
packages = ["src/splitzip"]
|
|
49
|
+
|
|
50
|
+
[tool.ruff]
|
|
51
|
+
line-length = 100
|
|
52
|
+
target-version = "py39"
|
|
53
|
+
|
|
54
|
+
[tool.ruff.lint]
|
|
55
|
+
select = ["E", "F", "W", "I", "UP", "B", "SIM"]
|
|
56
|
+
|
|
57
|
+
[tool.mypy]
|
|
58
|
+
python_version = "3.9"
|
|
59
|
+
strict = true
|
|
60
|
+
|
|
61
|
+
[tool.pytest.ini_options]
|
|
62
|
+
testpaths = ["tests"]
|
|
63
|
+
addopts = "-v --tb=short"
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
splitzip - Create split ZIP archives compatible with standard tools.
|
|
3
|
+
|
|
4
|
+
Create multi-part ZIP archives that can be extracted with Windows Explorer,
|
|
5
|
+
WinZip, 7-Zip, and other standard tools without requiring special software.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
>>> import splitzip
|
|
9
|
+
>>>
|
|
10
|
+
>>> # Simple one-liner
|
|
11
|
+
>>> splitzip.create("backup.zip", ["file1.txt", "data/"], split_size="100MB")
|
|
12
|
+
>>>
|
|
13
|
+
>>> # Context manager for more control
|
|
14
|
+
>>> with splitzip.SplitZipWriter("backup.zip", split_size="100MB") as zf:
|
|
15
|
+
... zf.write("file1.txt")
|
|
16
|
+
... zf.write("data/", recursive=True)
|
|
17
|
+
... zf.writestr("hello.txt", b"Hello, world!")
|
|
18
|
+
|
|
19
|
+
The resulting files will be named:
|
|
20
|
+
backup.z01, backup.z02, ..., backup.zip
|
|
21
|
+
|
|
22
|
+
The final .zip file contains the central directory and must be present
|
|
23
|
+
along with all .zXX files for extraction.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from .exceptions import (
|
|
27
|
+
CompressionError,
|
|
28
|
+
FileNotFoundInArchiveError,
|
|
29
|
+
IntegrityError,
|
|
30
|
+
SplitZipError,
|
|
31
|
+
VolumeTooSmallError,
|
|
32
|
+
VolumeError,
|
|
33
|
+
)
|
|
34
|
+
from .structures import Compression
|
|
35
|
+
from .utils import format_size, parse_size
|
|
36
|
+
from .writer import SplitZipWriter
|
|
37
|
+
|
|
38
|
+
__version__ = "0.1.0"
|
|
39
|
+
__all__ = [
|
|
40
|
+
# Main classes
|
|
41
|
+
"SplitZipWriter",
|
|
42
|
+
# Convenience functions
|
|
43
|
+
"create",
|
|
44
|
+
# Constants
|
|
45
|
+
"Compression",
|
|
46
|
+
"STORED",
|
|
47
|
+
"DEFLATED",
|
|
48
|
+
# Utilities
|
|
49
|
+
"parse_size",
|
|
50
|
+
"format_size",
|
|
51
|
+
# Exceptions
|
|
52
|
+
"SplitZipError",
|
|
53
|
+
"VolumeError",
|
|
54
|
+
"VolumeTooSmallError",
|
|
55
|
+
"CompressionError",
|
|
56
|
+
"IntegrityError",
|
|
57
|
+
"FileNotFoundInArchiveError",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
# Convenience aliases
|
|
61
|
+
STORED = Compression.STORED
|
|
62
|
+
DEFLATED = Compression.DEFLATED
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def create(
|
|
66
|
+
path: str,
|
|
67
|
+
files: list[str],
|
|
68
|
+
split_size: int | str,
|
|
69
|
+
compression: int = DEFLATED,
|
|
70
|
+
compresslevel: int = 6,
|
|
71
|
+
recursive: bool = True,
|
|
72
|
+
) -> list[str]:
|
|
73
|
+
"""
|
|
74
|
+
Create a split ZIP archive from a list of files/directories.
|
|
75
|
+
|
|
76
|
+
This is a convenience function for simple use cases. For more control,
|
|
77
|
+
use SplitZipWriter directly.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
path: Path for the final .zip file.
|
|
81
|
+
files: List of file/directory paths to include.
|
|
82
|
+
split_size: Maximum size per volume (e.g., "100MB", "700MiB", 104857600).
|
|
83
|
+
compression: Compression method (STORED or DEFLATED).
|
|
84
|
+
compresslevel: DEFLATE compression level 1-9 (default 6).
|
|
85
|
+
recursive: If True, add directory contents recursively.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
List of paths to all volume files created.
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
>>> splitzip.create(
|
|
92
|
+
... "backup.zip",
|
|
93
|
+
... ["documents/", "photos/", "important.pdf"],
|
|
94
|
+
... split_size="650MB" # CD-ROM size
|
|
95
|
+
... )
|
|
96
|
+
['backup.z01', 'backup.z02', 'backup.zip']
|
|
97
|
+
"""
|
|
98
|
+
with SplitZipWriter(
|
|
99
|
+
path,
|
|
100
|
+
split_size=split_size,
|
|
101
|
+
compression=compression,
|
|
102
|
+
compresslevel=compresslevel,
|
|
103
|
+
) as zf:
|
|
104
|
+
for file_path in files:
|
|
105
|
+
zf.write(file_path, recursive=recursive)
|
|
106
|
+
|
|
107
|
+
return [str(p) for p in zf.volume_paths]
|