klygo 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.
- klygo-0.1.0/PKG-INFO +151 -0
- klygo-0.1.0/README.md +131 -0
- klygo-0.1.0/klygo/__init__.py +18 -0
- klygo-0.1.0/klygo/archive/__init__.py +20 -0
- klygo-0.1.0/klygo/archive/_utils.py +7 -0
- klygo-0.1.0/klygo/archive/compress.py +119 -0
- klygo-0.1.0/klygo/archive/extract.py +183 -0
- klygo-0.1.0/klygo/archive/info.py +125 -0
- klygo-0.1.0/klygo/archive/list.py +108 -0
- klygo-0.1.0/klygo/archive/modify.py +166 -0
- klygo-0.1.0/klygo/archive/transform.py +234 -0
- klygo-0.1.0/klygo/datasets/__init__.py +14 -0
- klygo-0.1.0/klygo/datasets/_utils.py +135 -0
- klygo-0.1.0/klygo/datasets/info.py +68 -0
- klygo-0.1.0/klygo/datasets/merge.py +166 -0
- klygo-0.1.0/klygo/datasets/partition.py +179 -0
- klygo-0.1.0/klygo/datasets/remap.py +173 -0
- klygo-0.1.0/klygo/datasets/split.py +214 -0
- klygo-0.1.0/klygo/io/__init__.py +18 -0
- klygo-0.1.0/klygo/io/config.py +153 -0
- klygo-0.1.0/klygo/io/read.py +181 -0
- klygo-0.1.0/klygo/io/write.py +284 -0
- klygo-0.1.0/klygo/models/__init__.py +5 -0
- klygo-0.1.0/klygo/models/kernel.py +376 -0
- klygo-0.1.0/klygo/utils/__init__.py +0 -0
- klygo-0.1.0/klygo/validators/__init__.py +5 -0
- klygo-0.1.0/klygo/validators/archive/__init__.py +27 -0
- klygo-0.1.0/klygo/validators/archive/validators.py +268 -0
- klygo-0.1.0/klygo/validators/datasets/__init__.py +15 -0
- klygo-0.1.0/klygo/validators/datasets/validators.py +181 -0
- klygo-0.1.0/klygo/validators/io/__init__.py +8 -0
- klygo-0.1.0/klygo/validators/io/validators.py +113 -0
- klygo-0.1.0/klygo/validators/models/__init__.py +7 -0
- klygo-0.1.0/klygo/validators/models/validators.py +112 -0
- klygo-0.1.0/klygo/validators/type_validator.py +18 -0
- klygo-0.1.0/klygo.egg-info/PKG-INFO +151 -0
- klygo-0.1.0/klygo.egg-info/SOURCES.txt +40 -0
- klygo-0.1.0/klygo.egg-info/dependency_links.txt +1 -0
- klygo-0.1.0/klygo.egg-info/requires.txt +13 -0
- klygo-0.1.0/klygo.egg-info/top_level.txt +1 -0
- klygo-0.1.0/pyproject.toml +21 -0
- klygo-0.1.0/setup.cfg +4 -0
klygo-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: klygo
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: build>=1.5.1
|
|
8
|
+
Requires-Dist: numpy>=2.5.1
|
|
9
|
+
Requires-Dist: opencv-python>=5.0.0.93
|
|
10
|
+
Requires-Dist: pillow>=12.3.0
|
|
11
|
+
Requires-Dist: pydantic>=2.13.4
|
|
12
|
+
Requires-Dist: python-box>=7.4.1
|
|
13
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
14
|
+
Requires-Dist: ruamel-yaml>=0.19.1
|
|
15
|
+
Requires-Dist: tomlkit>=0.15.0
|
|
16
|
+
Requires-Dist: torch>=2.13.0
|
|
17
|
+
Requires-Dist: tqdm>=4.68.4
|
|
18
|
+
Requires-Dist: transformers>=5.13.0
|
|
19
|
+
Requires-Dist: twine>=6.2.0
|
|
20
|
+
|
|
21
|
+
# klygo
|
|
22
|
+
|
|
23
|
+
Thư viện Python hỗ trợ nén/giải nén file, xử lý bộ dữ liệu YOLO, đọc/ghi file cấu hình và nhận diện vật thể zero-shot.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Tính năng chính
|
|
28
|
+
|
|
29
|
+
- klygo.archive: Các thao tác với file nén ZIP (nén, giải nén, tìm kiếm, gộp, chia, thêm, xóa file) hỗ trợ hiển thị thanh tiến trình.
|
|
30
|
+
- klygo.datasets: Các công cụ quản lý và xử lý bộ dữ liệu YOLO (phân chia train/val/test, chia lại tỷ lệ tại chỗ, gộp nhiều dataset có ánh xạ lại class ID, và tách dataset theo class/tỷ lệ con).
|
|
31
|
+
- klygo.io: Đọc và ghi các file cấu hình YAML, JSON, TOML, tự động tạo thư mục, tự động phân giải đường dẫn tương đối và truy cập dạng thuộc tính qua Box.
|
|
32
|
+
- klygo.models: Lớp hỗ trợ nhận diện vật thể zero-shot (dựa trên Grounding DINO) trên ảnh và video, tự động xuất dữ liệu theo định dạng YOLO.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Cấu trúc thư mục
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
klygo/
|
|
40
|
+
├── archive/ # Các tiện ích nén và giải nén
|
|
41
|
+
├── datasets/ # Công cụ quản lý và phân chia bộ dữ liệu YOLO
|
|
42
|
+
├── io/ # Bộ đọc/ghi cấu hình YAML, JSON, TOML
|
|
43
|
+
├── models/ # Lớp nhận diện vật thể (Kernel)
|
|
44
|
+
└── validators/ # Bộ xác thực dữ liệu đầu vào
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Hướng dẫn sử dụng nhanh
|
|
50
|
+
|
|
51
|
+
### 1. Nén và giải nén (klygo.archive as ar)
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import klygo.archive as ar
|
|
55
|
+
|
|
56
|
+
# Nén thư mục và giải nén
|
|
57
|
+
ar.compress("src_directory/", "archive.zip")
|
|
58
|
+
ar.extract("archive.zip", output="destination_dir/", overwrite=True)
|
|
59
|
+
|
|
60
|
+
# Tìm kiếm file trong archive
|
|
61
|
+
files = ar.search("archive.zip", "images/*.jpg")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Xem tài liệu đầy đủ tại docs/archive/README.md.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### 2. Quản lý bộ dữ liệu YOLO (klygo.datasets)
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from klygo.datasets import partition, repartition, merge, split, remap_classes, get_dataset_info
|
|
72
|
+
|
|
73
|
+
# 1. Phân chia tập dữ liệu thô thành train/val/test
|
|
74
|
+
partition(source="raw_data.zip", output="dataset/", ratios=(0.8,), overwrite=True)
|
|
75
|
+
|
|
76
|
+
# 2. Hợp nhất hai bộ dữ liệu khác class tự động đổi class ID
|
|
77
|
+
merge(sources=["data1/", "data2.zip"], output="merged.zip", overwrite=True)
|
|
78
|
+
|
|
79
|
+
# 3. Tách nhỏ bộ dữ liệu theo từng class đối tượng riêng biệt
|
|
80
|
+
split(source="merged.zip", output_dir="split_classes/", by_class=True, overwrite=True)
|
|
81
|
+
|
|
82
|
+
# 4. Ánh xạ và đổi tên lớp dữ liệu
|
|
83
|
+
remap_classes(source="merged.zip", output="remapped.zip", class_map={0: 1, "apple": "red_apple"}, overwrite=True)
|
|
84
|
+
|
|
85
|
+
# 5. Lấy thông tin chi tiết của bộ dữ liệu YOLO
|
|
86
|
+
info = get_dataset_info("merged.zip")
|
|
87
|
+
print(info)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Xem tài liệu đầy đủ tại docs/datasets/README.md.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### 3. File cấu hình (klygo.io as io)
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
import klygo.io as io
|
|
100
|
+
|
|
101
|
+
# Ghi file cấu hình
|
|
102
|
+
config_data = {"learning_rate": 0.01, "epochs": 50}
|
|
103
|
+
io.write_file("configs/train_params.toml", config_data, overwrite=True)
|
|
104
|
+
|
|
105
|
+
# Đọc file cấu hình và truy cập bằng thuộc tính
|
|
106
|
+
cfg = io.Config("configs/train_params.toml").imread()
|
|
107
|
+
print(cfg.learning_rate) # 0.01
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Xem tài liệu đầy đủ tại docs/io/README.md.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### 4. Mô hình nhận diện (klygo.models.Kernel)
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from klygo.models import Kernel
|
|
118
|
+
|
|
119
|
+
# Khởi tạo mô hình Grounding DINO
|
|
120
|
+
kernel = Kernel()
|
|
121
|
+
|
|
122
|
+
# Chạy nhận diện trên video và xuất ra bộ dữ liệu YOLO
|
|
123
|
+
kernel.detect(
|
|
124
|
+
input_path="input_video.mp4",
|
|
125
|
+
prompt="car. traffic light.",
|
|
126
|
+
save_yolo_dir="dataset/"
|
|
127
|
+
)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Xem tài liệu đầy đủ tại docs/models/README.md.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Cài đặt
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
git clone https://github.com/your-username/klygo.git
|
|
138
|
+
cd klygo
|
|
139
|
+
uv sync
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Tài liệu chi tiết
|
|
145
|
+
|
|
146
|
+
Tất cả hướng dẫn đầy đủ đều được lưu tại thư mục docs:
|
|
147
|
+
* Hướng dẫn nén & giải nén: docs/archive/README.md
|
|
148
|
+
* Hướng dẫn xử lý bộ dữ liệu YOLO: docs/datasets/README.md
|
|
149
|
+
* Hướng dẫn cấu hình & IO: docs/io/README.md
|
|
150
|
+
* Hướng dẫn nhận diện vật thể: docs/models/README.md
|
|
151
|
+
# k l y g o
|
klygo-0.1.0/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# klygo
|
|
2
|
+
|
|
3
|
+
Thư viện Python hỗ trợ nén/giải nén file, xử lý bộ dữ liệu YOLO, đọc/ghi file cấu hình và nhận diện vật thể zero-shot.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Tính năng chính
|
|
8
|
+
|
|
9
|
+
- klygo.archive: Các thao tác với file nén ZIP (nén, giải nén, tìm kiếm, gộp, chia, thêm, xóa file) hỗ trợ hiển thị thanh tiến trình.
|
|
10
|
+
- klygo.datasets: Các công cụ quản lý và xử lý bộ dữ liệu YOLO (phân chia train/val/test, chia lại tỷ lệ tại chỗ, gộp nhiều dataset có ánh xạ lại class ID, và tách dataset theo class/tỷ lệ con).
|
|
11
|
+
- klygo.io: Đọc và ghi các file cấu hình YAML, JSON, TOML, tự động tạo thư mục, tự động phân giải đường dẫn tương đối và truy cập dạng thuộc tính qua Box.
|
|
12
|
+
- klygo.models: Lớp hỗ trợ nhận diện vật thể zero-shot (dựa trên Grounding DINO) trên ảnh và video, tự động xuất dữ liệu theo định dạng YOLO.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Cấu trúc thư mục
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
klygo/
|
|
20
|
+
├── archive/ # Các tiện ích nén và giải nén
|
|
21
|
+
├── datasets/ # Công cụ quản lý và phân chia bộ dữ liệu YOLO
|
|
22
|
+
├── io/ # Bộ đọc/ghi cấu hình YAML, JSON, TOML
|
|
23
|
+
├── models/ # Lớp nhận diện vật thể (Kernel)
|
|
24
|
+
└── validators/ # Bộ xác thực dữ liệu đầu vào
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Hướng dẫn sử dụng nhanh
|
|
30
|
+
|
|
31
|
+
### 1. Nén và giải nén (klygo.archive as ar)
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
import klygo.archive as ar
|
|
35
|
+
|
|
36
|
+
# Nén thư mục và giải nén
|
|
37
|
+
ar.compress("src_directory/", "archive.zip")
|
|
38
|
+
ar.extract("archive.zip", output="destination_dir/", overwrite=True)
|
|
39
|
+
|
|
40
|
+
# Tìm kiếm file trong archive
|
|
41
|
+
files = ar.search("archive.zip", "images/*.jpg")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Xem tài liệu đầy đủ tại docs/archive/README.md.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### 2. Quản lý bộ dữ liệu YOLO (klygo.datasets)
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from klygo.datasets import partition, repartition, merge, split, remap_classes, get_dataset_info
|
|
52
|
+
|
|
53
|
+
# 1. Phân chia tập dữ liệu thô thành train/val/test
|
|
54
|
+
partition(source="raw_data.zip", output="dataset/", ratios=(0.8,), overwrite=True)
|
|
55
|
+
|
|
56
|
+
# 2. Hợp nhất hai bộ dữ liệu khác class tự động đổi class ID
|
|
57
|
+
merge(sources=["data1/", "data2.zip"], output="merged.zip", overwrite=True)
|
|
58
|
+
|
|
59
|
+
# 3. Tách nhỏ bộ dữ liệu theo từng class đối tượng riêng biệt
|
|
60
|
+
split(source="merged.zip", output_dir="split_classes/", by_class=True, overwrite=True)
|
|
61
|
+
|
|
62
|
+
# 4. Ánh xạ và đổi tên lớp dữ liệu
|
|
63
|
+
remap_classes(source="merged.zip", output="remapped.zip", class_map={0: 1, "apple": "red_apple"}, overwrite=True)
|
|
64
|
+
|
|
65
|
+
# 5. Lấy thông tin chi tiết của bộ dữ liệu YOLO
|
|
66
|
+
info = get_dataset_info("merged.zip")
|
|
67
|
+
print(info)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Xem tài liệu đầy đủ tại docs/datasets/README.md.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### 3. File cấu hình (klygo.io as io)
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
import klygo.io as io
|
|
80
|
+
|
|
81
|
+
# Ghi file cấu hình
|
|
82
|
+
config_data = {"learning_rate": 0.01, "epochs": 50}
|
|
83
|
+
io.write_file("configs/train_params.toml", config_data, overwrite=True)
|
|
84
|
+
|
|
85
|
+
# Đọc file cấu hình và truy cập bằng thuộc tính
|
|
86
|
+
cfg = io.Config("configs/train_params.toml").imread()
|
|
87
|
+
print(cfg.learning_rate) # 0.01
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Xem tài liệu đầy đủ tại docs/io/README.md.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### 4. Mô hình nhận diện (klygo.models.Kernel)
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from klygo.models import Kernel
|
|
98
|
+
|
|
99
|
+
# Khởi tạo mô hình Grounding DINO
|
|
100
|
+
kernel = Kernel()
|
|
101
|
+
|
|
102
|
+
# Chạy nhận diện trên video và xuất ra bộ dữ liệu YOLO
|
|
103
|
+
kernel.detect(
|
|
104
|
+
input_path="input_video.mp4",
|
|
105
|
+
prompt="car. traffic light.",
|
|
106
|
+
save_yolo_dir="dataset/"
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Xem tài liệu đầy đủ tại docs/models/README.md.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Cài đặt
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
git clone https://github.com/your-username/klygo.git
|
|
118
|
+
cd klygo
|
|
119
|
+
uv sync
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Tài liệu chi tiết
|
|
125
|
+
|
|
126
|
+
Tất cả hướng dẫn đầy đủ đều được lưu tại thư mục docs:
|
|
127
|
+
* Hướng dẫn nén & giải nén: docs/archive/README.md
|
|
128
|
+
* Hướng dẫn xử lý bộ dữ liệu YOLO: docs/datasets/README.md
|
|
129
|
+
* Hướng dẫn cấu hình & IO: docs/io/README.md
|
|
130
|
+
* Hướng dẫn nhận diện vật thể: docs/models/README.md
|
|
131
|
+
# k l y g o
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from . import archive
|
|
2
|
+
from . import datasets
|
|
3
|
+
from . import io
|
|
4
|
+
from . import models
|
|
5
|
+
from . import utils
|
|
6
|
+
from . import validators
|
|
7
|
+
|
|
8
|
+
__version__ = "1.0.1"
|
|
9
|
+
__author__ = "IchigoMazone"
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"archive",
|
|
13
|
+
"datasets",
|
|
14
|
+
"io",
|
|
15
|
+
"models",
|
|
16
|
+
"utils",
|
|
17
|
+
"validators",
|
|
18
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from .compress import compress
|
|
2
|
+
from .extract import extract, extract_file
|
|
3
|
+
from .list import list_files, search
|
|
4
|
+
from .info import get_info, test
|
|
5
|
+
from .modify import add, remove
|
|
6
|
+
from .transform import merge, split
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"compress",
|
|
10
|
+
"extract",
|
|
11
|
+
"extract_file",
|
|
12
|
+
"list_files",
|
|
13
|
+
"search",
|
|
14
|
+
"get_info",
|
|
15
|
+
"test",
|
|
16
|
+
"add",
|
|
17
|
+
"remove",
|
|
18
|
+
"merge",
|
|
19
|
+
"split",
|
|
20
|
+
]
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from zipfile import ZipFile, ZIP_DEFLATED
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
|
|
6
|
+
from klygo.validators.archive import Compress
|
|
7
|
+
from klygo.archive._utils import _human_size
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def compress(
|
|
11
|
+
source: str | Path,
|
|
12
|
+
output: str | Path,
|
|
13
|
+
format: str = "zip",
|
|
14
|
+
overwrite: bool = False,
|
|
15
|
+
verbose: bool = True,
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Compress a file or directory into a ZIP archive.
|
|
18
|
+
|
|
19
|
+
When ``source`` is a directory, all files are added recursively
|
|
20
|
+
while preserving the internal directory structure. Parent-level
|
|
21
|
+
directory name is kept as the root inside the archive.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
source : str or Path
|
|
26
|
+
Path to the file or directory to compress.
|
|
27
|
+
output : str or Path
|
|
28
|
+
Destination path for the archive (e.g. ``"data.zip"``).
|
|
29
|
+
Parent directories are created automatically if they do not exist.
|
|
30
|
+
format : str, optional
|
|
31
|
+
Archive format. Currently only ``"zip"`` is supported.
|
|
32
|
+
Default is ``"zip"``.
|
|
33
|
+
overwrite : bool, optional
|
|
34
|
+
If *True*, silently overwrite ``output`` when it already exists.
|
|
35
|
+
If *False* (default) and ``output`` exists, raises ``FileExistsError``.
|
|
36
|
+
verbose : bool, optional
|
|
37
|
+
If *True* (default), display a coloured progress bar and print
|
|
38
|
+
the final archive size on completion.
|
|
39
|
+
|
|
40
|
+
Returns
|
|
41
|
+
-------
|
|
42
|
+
None
|
|
43
|
+
|
|
44
|
+
Raises
|
|
45
|
+
------
|
|
46
|
+
TypeError
|
|
47
|
+
If any argument has the wrong type.
|
|
48
|
+
FileNotFoundError
|
|
49
|
+
If ``source`` does not exist.
|
|
50
|
+
FileExistsError
|
|
51
|
+
If ``output`` already exists and ``overwrite`` is *False*.
|
|
52
|
+
ValueError
|
|
53
|
+
If ``format`` is not supported, or ``output`` has the wrong extension.
|
|
54
|
+
|
|
55
|
+
Examples
|
|
56
|
+
--------
|
|
57
|
+
Compress a single file:
|
|
58
|
+
|
|
59
|
+
>>> compress("report.csv", "report.zip")
|
|
60
|
+
|
|
61
|
+
Compress an entire directory, overwriting any existing archive:
|
|
62
|
+
|
|
63
|
+
>>> compress("my_dataset/", "dataset.zip", overwrite=True)
|
|
64
|
+
|
|
65
|
+
Compress silently (no progress bar):
|
|
66
|
+
|
|
67
|
+
>>> compress("images/", "images.zip", verbose=False)
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
params = Compress(
|
|
71
|
+
source=source,
|
|
72
|
+
output=output,
|
|
73
|
+
format=format,
|
|
74
|
+
overwrite=overwrite,
|
|
75
|
+
verbose=verbose,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
source_path: Path = params.source
|
|
79
|
+
output_path: Path = params.output
|
|
80
|
+
|
|
81
|
+
# Collect all files to compress
|
|
82
|
+
if source_path.is_dir():
|
|
83
|
+
all_files: list[Path] = sorted(
|
|
84
|
+
f for f in source_path.rglob("*") if f.is_file()
|
|
85
|
+
)
|
|
86
|
+
else:
|
|
87
|
+
all_files = [source_path]
|
|
88
|
+
|
|
89
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
90
|
+
|
|
91
|
+
with ZipFile(output_path, mode="w", compression=ZIP_DEFLATED) as zf:
|
|
92
|
+
bar = (
|
|
93
|
+
tqdm(
|
|
94
|
+
total=len(all_files) or 1,
|
|
95
|
+
desc="Compressing",
|
|
96
|
+
unit="file",
|
|
97
|
+
colour="green",
|
|
98
|
+
bar_format="{l_bar}{bar:30}{r_bar}",
|
|
99
|
+
)
|
|
100
|
+
if verbose
|
|
101
|
+
else None
|
|
102
|
+
)
|
|
103
|
+
for file in all_files:
|
|
104
|
+
arcname = (
|
|
105
|
+
file.relative_to(source_path.parent)
|
|
106
|
+
if source_path.is_dir()
|
|
107
|
+
else file.name
|
|
108
|
+
)
|
|
109
|
+
zf.write(file, arcname=arcname)
|
|
110
|
+
if bar is not None:
|
|
111
|
+
bar.update(1)
|
|
112
|
+
if bar is not None:
|
|
113
|
+
if not all_files:
|
|
114
|
+
bar.update(1)
|
|
115
|
+
bar.close()
|
|
116
|
+
|
|
117
|
+
if verbose:
|
|
118
|
+
total_size = output_path.stat().st_size
|
|
119
|
+
print(f"Done. Archive size: {_human_size(total_size)}")
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
from zipfile import ZipFile
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
|
|
6
|
+
from klygo.validators.archive import Extract, ExtractFile
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def extract(
|
|
10
|
+
source: str | Path,
|
|
11
|
+
output: str | Path = ".",
|
|
12
|
+
overwrite: bool = False,
|
|
13
|
+
verbose: bool = True,
|
|
14
|
+
) -> None:
|
|
15
|
+
"""Extract all contents of an archive to a directory.
|
|
16
|
+
|
|
17
|
+
The full directory structure stored inside the archive is
|
|
18
|
+
recreated under ``output``. The output directory is created
|
|
19
|
+
automatically if it does not exist.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
source : str or Path
|
|
24
|
+
Path to the archive file to extract (e.g. ``"data.zip"``).
|
|
25
|
+
output : str or Path, optional
|
|
26
|
+
Directory where the archive contents will be extracted.
|
|
27
|
+
Defaults to the current working directory (``"."``).
|
|
28
|
+
overwrite : bool, optional
|
|
29
|
+
If *True*, overwrite files that already exist in ``output``.
|
|
30
|
+
If *False* (default) and conflicting files exist, raises
|
|
31
|
+
``FileExistsError`` listing the first offending names.
|
|
32
|
+
verbose : bool, optional
|
|
33
|
+
If *True* (default), display a coloured progress bar and print
|
|
34
|
+
the total number of extracted files on completion.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
None
|
|
39
|
+
|
|
40
|
+
Raises
|
|
41
|
+
------
|
|
42
|
+
TypeError
|
|
43
|
+
If any argument has the wrong type.
|
|
44
|
+
FileNotFoundError
|
|
45
|
+
If ``source`` does not exist.
|
|
46
|
+
ValueError
|
|
47
|
+
If ``source`` is not a supported archive format.
|
|
48
|
+
FileExistsError
|
|
49
|
+
If files in the archive already exist at the destination
|
|
50
|
+
and ``overwrite`` is *False*.
|
|
51
|
+
|
|
52
|
+
Examples
|
|
53
|
+
--------
|
|
54
|
+
Extract to a specific folder:
|
|
55
|
+
|
|
56
|
+
>>> extract("data.zip", output="data/")
|
|
57
|
+
|
|
58
|
+
Extract and overwrite any existing files:
|
|
59
|
+
|
|
60
|
+
>>> extract("data.zip", output="data/", overwrite=True)
|
|
61
|
+
|
|
62
|
+
Extract silently:
|
|
63
|
+
|
|
64
|
+
>>> extract("data.zip", output="data/", verbose=False)
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
params = Extract(
|
|
68
|
+
source=source,
|
|
69
|
+
output=output,
|
|
70
|
+
overwrite=overwrite,
|
|
71
|
+
verbose=verbose,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
source_path: Path = params.source
|
|
75
|
+
output_path: Path = params.output
|
|
76
|
+
|
|
77
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
78
|
+
|
|
79
|
+
with ZipFile(source_path, mode="r") as zf:
|
|
80
|
+
members = zf.infolist()
|
|
81
|
+
|
|
82
|
+
if not overwrite:
|
|
83
|
+
existing = [
|
|
84
|
+
m for m in members
|
|
85
|
+
if (output_path / m.filename).exists()
|
|
86
|
+
]
|
|
87
|
+
if existing:
|
|
88
|
+
names = ", ".join(m.filename for m in existing[:5])
|
|
89
|
+
suffix = f"… (+{len(existing) - 5} more)" if len(existing) > 5 else ""
|
|
90
|
+
raise FileExistsError(
|
|
91
|
+
f"Files already exist in output directory: {names}{suffix}. "
|
|
92
|
+
"Use overwrite=True to replace them."
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
iterator = (
|
|
96
|
+
tqdm(
|
|
97
|
+
members,
|
|
98
|
+
desc="Extracting",
|
|
99
|
+
unit="file",
|
|
100
|
+
colour="cyan",
|
|
101
|
+
bar_format="{l_bar}{bar:30}{r_bar}",
|
|
102
|
+
)
|
|
103
|
+
if verbose
|
|
104
|
+
else iter(members)
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
for member in iterator:
|
|
108
|
+
zf.extract(member, path=output_path)
|
|
109
|
+
|
|
110
|
+
if verbose:
|
|
111
|
+
print(f"Done. Extracted {len(members)} file(s) to '{output_path}'")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def extract_file(
|
|
115
|
+
source: str | Path,
|
|
116
|
+
filename: str,
|
|
117
|
+
output: str | Path = ".",
|
|
118
|
+
overwrite: bool = False,
|
|
119
|
+
) -> None:
|
|
120
|
+
"""Extract a single file from an archive without unpacking everything.
|
|
121
|
+
|
|
122
|
+
Use :func:`list_files` to discover the exact ``filename`` string
|
|
123
|
+
as it is stored inside the archive, then pass that value here.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
source : str or Path
|
|
128
|
+
Path to the archive file.
|
|
129
|
+
filename : str
|
|
130
|
+
Path of the target file *inside* the archive, exactly as returned
|
|
131
|
+
by :func:`list_files` (e.g. ``"images/frame_001.jpg"``).
|
|
132
|
+
output : str or Path, optional
|
|
133
|
+
Directory where the file will be written.
|
|
134
|
+
Defaults to the current working directory (``"."``).
|
|
135
|
+
overwrite : bool, optional
|
|
136
|
+
If *True*, overwrite the file if it already exists at the destination.
|
|
137
|
+
Default is *False*.
|
|
138
|
+
|
|
139
|
+
Returns
|
|
140
|
+
-------
|
|
141
|
+
None
|
|
142
|
+
|
|
143
|
+
Raises
|
|
144
|
+
------
|
|
145
|
+
TypeError
|
|
146
|
+
If any argument has the wrong type.
|
|
147
|
+
FileNotFoundError
|
|
148
|
+
If ``source`` does not exist.
|
|
149
|
+
KeyError
|
|
150
|
+
If ``filename`` is not found inside the archive.
|
|
151
|
+
FileExistsError
|
|
152
|
+
If the destination file already exists and ``overwrite`` is *False*.
|
|
153
|
+
|
|
154
|
+
Examples
|
|
155
|
+
--------
|
|
156
|
+
>>> extract_file("data.zip", "images/frame_001.jpg", output="out/")
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
params = ExtractFile(
|
|
160
|
+
source=source,
|
|
161
|
+
filename=filename,
|
|
162
|
+
output=output,
|
|
163
|
+
overwrite=overwrite,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
output_path: Path = params.output
|
|
167
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
168
|
+
|
|
169
|
+
with ZipFile(params.source, mode="r") as zf:
|
|
170
|
+
names = zf.namelist()
|
|
171
|
+
if params.filename not in names:
|
|
172
|
+
raise KeyError(
|
|
173
|
+
f"'{params.filename}' not found in archive. "
|
|
174
|
+
f"Use list_files() to see available files."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
target = output_path / Path(params.filename).name
|
|
178
|
+
if target.exists() and not params.overwrite:
|
|
179
|
+
raise FileExistsError(
|
|
180
|
+
f"file already exists: {target}. Use overwrite=True."
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
zf.extract(params.filename, path=output_path)
|