ilovetools 0.2.3__tar.gz → 0.2.5__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 (65) hide show
  1. {ilovetools-0.2.3/ilovetools.egg-info → ilovetools-0.2.5}/PKG-INFO +27 -3
  2. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/__init__.py +1 -1
  3. ilovetools-0.2.5/ilovetools/automation/__init__.py +25 -0
  4. ilovetools-0.2.5/ilovetools/automation/file_organizer.py +523 -0
  5. ilovetools-0.2.5/ilovetools/conversion/__init__.py +41 -0
  6. ilovetools-0.2.5/ilovetools/conversion/config_converter.py +769 -0
  7. ilovetools-0.2.5/ilovetools/email/__init__.py +23 -0
  8. ilovetools-0.2.5/ilovetools/email/template_engine.py +457 -0
  9. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/__init__.py +23 -0
  10. ilovetools-0.2.5/ilovetools/ml/anomaly_detection.py +396 -0
  11. ilovetools-0.2.5/ilovetools/security/__init__.py +25 -0
  12. ilovetools-0.2.5/ilovetools/security/password_checker.py +467 -0
  13. ilovetools-0.2.5/ilovetools/utils/__init__.py +84 -0
  14. ilovetools-0.2.5/ilovetools/utils/cache_system.py +618 -0
  15. ilovetools-0.2.5/ilovetools/utils/logger.py +438 -0
  16. ilovetools-0.2.5/ilovetools/utils/rate_limiter.py +559 -0
  17. ilovetools-0.2.5/ilovetools/utils/retry.py +388 -0
  18. ilovetools-0.2.5/ilovetools/validation/__init__.py +41 -0
  19. ilovetools-0.2.5/ilovetools/validation/data_validator.py +692 -0
  20. ilovetools-0.2.5/ilovetools/web/__init__.py +50 -0
  21. ilovetools-0.2.5/ilovetools/web/scraper.py +557 -0
  22. ilovetools-0.2.5/ilovetools/web/url_shortener.py +476 -0
  23. {ilovetools-0.2.3 → ilovetools-0.2.5/ilovetools.egg-info}/PKG-INFO +27 -3
  24. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools.egg-info/SOURCES.txt +14 -0
  25. ilovetools-0.2.5/ilovetools.egg-info/requires.txt +27 -0
  26. {ilovetools-0.2.3 → ilovetools-0.2.5}/pyproject.toml +35 -3
  27. {ilovetools-0.2.3 → ilovetools-0.2.5}/setup.py +1 -1
  28. ilovetools-0.2.3/ilovetools/automation/__init__.py +0 -5
  29. ilovetools-0.2.3/ilovetools/conversion/__init__.py +0 -5
  30. ilovetools-0.2.3/ilovetools/security/__init__.py +0 -5
  31. ilovetools-0.2.3/ilovetools/utils/__init__.py +0 -5
  32. ilovetools-0.2.3/ilovetools/validation/__init__.py +0 -5
  33. ilovetools-0.2.3/ilovetools/web/__init__.py +0 -5
  34. {ilovetools-0.2.3 → ilovetools-0.2.5}/LICENSE +0 -0
  35. {ilovetools-0.2.3 → ilovetools-0.2.5}/MANIFEST.in +0 -0
  36. {ilovetools-0.2.3 → ilovetools-0.2.5}/README.md +0 -0
  37. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ai/__init__.py +0 -0
  38. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ai/embeddings.py +0 -0
  39. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ai/inference.py +0 -0
  40. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ai/llm_helpers.py +0 -0
  41. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/audio/__init__.py +0 -0
  42. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/data/__init__.py +0 -0
  43. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/data/feature_engineering.py +0 -0
  44. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/data/preprocessing.py +0 -0
  45. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/database/__init__.py +0 -0
  46. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/datetime/__init__.py +0 -0
  47. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/files/__init__.py +0 -0
  48. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/image/__init__.py +0 -0
  49. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/clustering.py +0 -0
  50. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/cross_validation.py +0 -0
  51. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/dimensionality.py +0 -0
  52. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/ensemble.py +0 -0
  53. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/feature_selection.py +0 -0
  54. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/imbalanced.py +0 -0
  55. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/interpretation.py +0 -0
  56. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/metrics.py +0 -0
  57. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/pipeline.py +0 -0
  58. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/timeseries.py +0 -0
  59. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/ml/tuning.py +0 -0
  60. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools/text/__init__.py +0 -0
  61. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools.egg-info/dependency_links.txt +0 -0
  62. {ilovetools-0.2.3 → ilovetools-0.2.5}/ilovetools.egg-info/top_level.txt +0 -0
  63. {ilovetools-0.2.3 → ilovetools-0.2.5}/requirements.txt +0 -0
  64. {ilovetools-0.2.3 → ilovetools-0.2.5}/setup.cfg +0 -0
  65. {ilovetools-0.2.3 → ilovetools-0.2.5}/tests/__init__.py +0 -0
@@ -1,19 +1,20 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ilovetools
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: A comprehensive Python utility library with modular tools for AI/ML, data processing, and daily programming needs
5
5
  Home-page: https://github.com/AliMehdi512/ilovetools
6
6
  Author: Ali Mehdi
7
7
  Author-email: Ali Mehdi <ali.mehdi.dev579@gmail.com>
8
- License: MIT
8
+ License-Expression: MIT
9
9
  Project-URL: Homepage, https://github.com/AliMehdi512/ilovetools
10
10
  Project-URL: Repository, https://github.com/AliMehdi512/ilovetools
11
11
  Project-URL: Issues, https://github.com/AliMehdi512/ilovetools/issues
12
+ Project-URL: Bug Reports, https://github.com/AliMehdi512/ilovetools/issues
13
+ Project-URL: Source, https://github.com/AliMehdi512/ilovetools
12
14
  Keywords: utilities,tools,ai,ml,data-processing,automation
13
15
  Classifier: Development Status :: 3 - Alpha
14
16
  Classifier: Intended Audience :: Developers
15
17
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
- Classifier: License :: OSI Approved :: MIT License
17
18
  Classifier: Programming Language :: Python :: 3
18
19
  Classifier: Programming Language :: Python :: 3.8
19
20
  Classifier: Programming Language :: Python :: 3.9
@@ -23,6 +24,29 @@ Classifier: Programming Language :: Python :: 3.12
23
24
  Requires-Python: >=3.8
24
25
  Description-Content-Type: text/markdown
25
26
  License-File: LICENSE
27
+ Requires-Dist: requests>=2.31.0
28
+ Requires-Dist: numpy>=1.24.0
29
+ Requires-Dist: pandas>=2.0.0
30
+ Provides-Extra: ai
31
+ Requires-Dist: openai>=1.0.0; extra == "ai"
32
+ Requires-Dist: transformers>=4.30.0; extra == "ai"
33
+ Requires-Dist: torch>=2.0.0; extra == "ai"
34
+ Requires-Dist: sentence-transformers>=2.2.0; extra == "ai"
35
+ Provides-Extra: image
36
+ Requires-Dist: Pillow>=10.0.0; extra == "image"
37
+ Requires-Dist: opencv-python>=4.8.0; extra == "image"
38
+ Provides-Extra: audio
39
+ Requires-Dist: librosa>=0.10.0; extra == "audio"
40
+ Requires-Dist: soundfile>=0.12.0; extra == "audio"
41
+ Provides-Extra: all
42
+ Requires-Dist: openai>=1.0.0; extra == "all"
43
+ Requires-Dist: transformers>=4.30.0; extra == "all"
44
+ Requires-Dist: torch>=2.0.0; extra == "all"
45
+ Requires-Dist: sentence-transformers>=2.2.0; extra == "all"
46
+ Requires-Dist: Pillow>=10.0.0; extra == "all"
47
+ Requires-Dist: opencv-python>=4.8.0; extra == "all"
48
+ Requires-Dist: librosa>=0.10.0; extra == "all"
49
+ Requires-Dist: soundfile>=0.12.0; extra == "all"
26
50
  Dynamic: author
27
51
  Dynamic: home-page
28
52
  Dynamic: license-file
@@ -2,7 +2,7 @@
2
2
  ilovetools - A comprehensive Python utility library
3
3
  """
4
4
 
5
- __version__ = "0.2.3"
5
+ __version__ = "0.2.5"
6
6
  __author__ = "Ali Mehdi"
7
7
  __email__ = "ali.mehdi.dev579@gmail.com"
8
8
 
@@ -0,0 +1,25 @@
1
+ """
2
+ Task automation utilities
3
+ """
4
+
5
+ from .file_organizer import (
6
+ organize_ext,
7
+ organize_date,
8
+ organize_size,
9
+ organize_pattern,
10
+ scan_directory,
11
+ move_files_safely,
12
+ create_folder_structure,
13
+ undo_organization,
14
+ )
15
+
16
+ __all__ = [
17
+ 'organize_ext',
18
+ 'organize_date',
19
+ 'organize_size',
20
+ 'organize_pattern',
21
+ 'scan_directory',
22
+ 'move_files_safely',
23
+ 'create_folder_structure',
24
+ 'undo_organization',
25
+ ]
@@ -0,0 +1,523 @@
1
+ """
2
+ File Organization Utility
3
+ Automatically organize files by type, date, or custom rules
4
+ """
5
+
6
+ import os
7
+ from typing import Dict, List, Optional, Callable
8
+ from datetime import datetime
9
+ import shutil
10
+
11
+ __all__ = [
12
+ 'organize_by_extension',
13
+ 'organize_by_date',
14
+ 'organize_by_size',
15
+ 'organize_by_name_pattern',
16
+ 'create_folder_structure',
17
+ 'move_files_safely',
18
+ 'get_file_categories',
19
+ 'scan_directory',
20
+ 'undo_organization',
21
+ 'organize_ext',
22
+ 'organize_date',
23
+ 'organize_size',
24
+ 'organize_pattern',
25
+ ]
26
+
27
+
28
+ # File type categories
29
+ FILE_CATEGORIES = {
30
+ 'Images': ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp', '.ico'],
31
+ 'Videos': ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm'],
32
+ 'Audio': ['.mp3', '.wav', '.flac', '.aac', '.ogg', '.wma', '.m4a'],
33
+ 'Documents': ['.pdf', '.doc', '.docx', '.txt', '.rtf', '.odt', '.pages'],
34
+ 'Spreadsheets': ['.xls', '.xlsx', '.csv', '.ods', '.numbers'],
35
+ 'Presentations': ['.ppt', '.pptx', '.key', '.odp'],
36
+ 'Archives': ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2'],
37
+ 'Code': ['.py', '.js', '.java', '.cpp', '.c', '.html', '.css', '.php', '.rb', '.go'],
38
+ 'Executables': ['.exe', '.app', '.dmg', '.deb', '.rpm'],
39
+ 'Others': []
40
+ }
41
+
42
+
43
+ def get_file_categories() -> Dict[str, List[str]]:
44
+ """
45
+ Get predefined file categories.
46
+
47
+ Returns:
48
+ dict: File categories with extensions
49
+
50
+ Examples:
51
+ >>> from ilovetools.automation import get_file_categories
52
+
53
+ >>> categories = get_file_categories()
54
+ >>> print(categories['Images'])
55
+ ['.jpg', '.jpeg', '.png', ...]
56
+ """
57
+ return FILE_CATEGORIES.copy()
58
+
59
+
60
+ def scan_directory(
61
+ directory: str,
62
+ recursive: bool = False,
63
+ include_hidden: bool = False
64
+ ) -> Dict[str, List[str]]:
65
+ """
66
+ Scan directory and categorize files.
67
+
68
+ Args:
69
+ directory: Directory path to scan
70
+ recursive: Scan subdirectories
71
+ include_hidden: Include hidden files
72
+
73
+ Returns:
74
+ dict: Categorized file paths
75
+
76
+ Examples:
77
+ >>> from ilovetools.automation import scan_directory
78
+
79
+ >>> files = scan_directory('/path/to/folder')
80
+ >>> print(files['Images'])
81
+ ['/path/to/folder/photo.jpg', ...]
82
+ """
83
+ if not os.path.exists(directory):
84
+ raise ValueError(f"Directory does not exist: {directory}")
85
+
86
+ categorized = {category: [] for category in FILE_CATEGORIES.keys()}
87
+
88
+ if recursive:
89
+ for root, dirs, files in os.walk(directory):
90
+ if not include_hidden:
91
+ files = [f for f in files if not f.startswith('.')]
92
+ dirs[:] = [d for d in dirs if not d.startswith('.')]
93
+
94
+ for file in files:
95
+ filepath = os.path.join(root, file)
96
+ ext = os.path.splitext(file)[1].lower()
97
+
98
+ categorized_flag = False
99
+ for category, extensions in FILE_CATEGORIES.items():
100
+ if ext in extensions:
101
+ categorized[category].append(filepath)
102
+ categorized_flag = True
103
+ break
104
+
105
+ if not categorized_flag:
106
+ categorized['Others'].append(filepath)
107
+ else:
108
+ files = os.listdir(directory)
109
+ if not include_hidden:
110
+ files = [f for f in files if not f.startswith('.')]
111
+
112
+ for file in files:
113
+ filepath = os.path.join(directory, file)
114
+ if os.path.isfile(filepath):
115
+ ext = os.path.splitext(file)[1].lower()
116
+
117
+ categorized_flag = False
118
+ for category, extensions in FILE_CATEGORIES.items():
119
+ if ext in extensions:
120
+ categorized[category].append(filepath)
121
+ categorized_flag = True
122
+ break
123
+
124
+ if not categorized_flag:
125
+ categorized['Others'].append(filepath)
126
+
127
+ return categorized
128
+
129
+
130
+ def create_folder_structure(
131
+ base_directory: str,
132
+ folders: List[str],
133
+ dry_run: bool = False
134
+ ) -> Dict[str, str]:
135
+ """
136
+ Create folder structure for organization.
137
+
138
+ Args:
139
+ base_directory: Base directory path
140
+ folders: List of folder names to create
141
+ dry_run: Preview without creating
142
+
143
+ Returns:
144
+ dict: Created folder paths
145
+
146
+ Examples:
147
+ >>> from ilovetools.automation import create_folder_structure
148
+
149
+ >>> folders = create_folder_structure(
150
+ ... '/path/to/organize',
151
+ ... ['Images', 'Videos', 'Documents']
152
+ ... )
153
+ >>> print(folders)
154
+ {'Images': '/path/to/organize/Images', ...}
155
+ """
156
+ created = {}
157
+
158
+ for folder in folders:
159
+ folder_path = os.path.join(base_directory, folder)
160
+ created[folder] = folder_path
161
+
162
+ if not dry_run:
163
+ os.makedirs(folder_path, exist_ok=True)
164
+
165
+ return created
166
+
167
+
168
+ def move_files_safely(
169
+ files: List[str],
170
+ destination: str,
171
+ dry_run: bool = False,
172
+ overwrite: bool = False
173
+ ) -> Dict[str, str]:
174
+ """
175
+ Move files safely with conflict handling.
176
+
177
+ Args:
178
+ files: List of file paths to move
179
+ destination: Destination directory
180
+ dry_run: Preview without moving
181
+ overwrite: Overwrite existing files
182
+
183
+ Returns:
184
+ dict: Moved file mappings (old -> new)
185
+
186
+ Examples:
187
+ >>> from ilovetools.automation import move_files_safely
188
+
189
+ >>> moved = move_files_safely(
190
+ ... ['/path/file1.jpg', '/path/file2.jpg'],
191
+ ... '/path/Images',
192
+ ... dry_run=True
193
+ ... )
194
+ >>> print(moved)
195
+ {'/path/file1.jpg': '/path/Images/file1.jpg', ...}
196
+ """
197
+ moved = {}
198
+
199
+ for filepath in files:
200
+ if not os.path.exists(filepath):
201
+ continue
202
+
203
+ filename = os.path.basename(filepath)
204
+ dest_path = os.path.join(destination, filename)
205
+
206
+ # Handle conflicts
207
+ if os.path.exists(dest_path) and not overwrite:
208
+ base, ext = os.path.splitext(filename)
209
+ counter = 1
210
+ while os.path.exists(dest_path):
211
+ new_filename = f"{base}_{counter}{ext}"
212
+ dest_path = os.path.join(destination, new_filename)
213
+ counter += 1
214
+
215
+ moved[filepath] = dest_path
216
+
217
+ if not dry_run:
218
+ shutil.move(filepath, dest_path)
219
+
220
+ return moved
221
+
222
+
223
+ def organize_by_extension(
224
+ directory: str,
225
+ dry_run: bool = False,
226
+ recursive: bool = False,
227
+ custom_categories: Optional[Dict[str, List[str]]] = None
228
+ ) -> Dict[str, Dict[str, str]]:
229
+ """
230
+ Organize files by extension into categorized folders.
231
+
232
+ Alias: organize_ext()
233
+
234
+ Args:
235
+ directory: Directory to organize
236
+ dry_run: Preview without organizing
237
+ recursive: Include subdirectories
238
+ custom_categories: Custom file categories
239
+
240
+ Returns:
241
+ dict: Organization results
242
+
243
+ Examples:
244
+ >>> from ilovetools.automation import organize_ext
245
+
246
+ >>> result = organize_ext('/path/to/messy', dry_run=True)
247
+ >>> print(result['Images'])
248
+ {'/path/photo.jpg': '/path/Images/photo.jpg', ...}
249
+ """
250
+ categories = custom_categories or FILE_CATEGORIES
251
+
252
+ # Scan directory
253
+ categorized = scan_directory(directory, recursive=recursive)
254
+
255
+ # Create folder structure
256
+ folders_to_create = [cat for cat, files in categorized.items() if files]
257
+ folder_paths = create_folder_structure(directory, folders_to_create, dry_run)
258
+
259
+ # Move files
260
+ results = {}
261
+ for category, files in categorized.items():
262
+ if files and category in folder_paths:
263
+ moved = move_files_safely(files, folder_paths[category], dry_run)
264
+ results[category] = moved
265
+
266
+ return results
267
+
268
+
269
+ # Alias
270
+ organize_ext = organize_by_extension
271
+
272
+
273
+ def organize_by_date(
274
+ directory: str,
275
+ date_format: str = '%Y-%m',
276
+ dry_run: bool = False,
277
+ use_modified_date: bool = True
278
+ ) -> Dict[str, Dict[str, str]]:
279
+ """
280
+ Organize files by date into folders.
281
+
282
+ Alias: organize_date()
283
+
284
+ Args:
285
+ directory: Directory to organize
286
+ date_format: Date format for folder names (%Y-%m, %Y, %Y-%m-%d)
287
+ dry_run: Preview without organizing
288
+ use_modified_date: Use modified date (else creation date)
289
+
290
+ Returns:
291
+ dict: Organization results
292
+
293
+ Examples:
294
+ >>> from ilovetools.automation import organize_date
295
+
296
+ >>> result = organize_date('/path/to/photos', date_format='%Y-%m')
297
+ >>> print(result.keys())
298
+ dict_keys(['2024-01', '2024-02', ...])
299
+ """
300
+ if not os.path.exists(directory):
301
+ raise ValueError(f"Directory does not exist: {directory}")
302
+
303
+ # Scan files
304
+ files = []
305
+ for item in os.listdir(directory):
306
+ filepath = os.path.join(directory, item)
307
+ if os.path.isfile(filepath):
308
+ files.append(filepath)
309
+
310
+ # Group by date
311
+ date_groups = {}
312
+ for filepath in files:
313
+ if use_modified_date:
314
+ timestamp = os.path.getmtime(filepath)
315
+ else:
316
+ timestamp = os.path.getctime(filepath)
317
+
318
+ date_obj = datetime.fromtimestamp(timestamp)
319
+ date_str = date_obj.strftime(date_format)
320
+
321
+ if date_str not in date_groups:
322
+ date_groups[date_str] = []
323
+ date_groups[date_str].append(filepath)
324
+
325
+ # Create folders and move files
326
+ results = {}
327
+ for date_str, file_list in date_groups.items():
328
+ folder_path = os.path.join(directory, date_str)
329
+
330
+ if not dry_run:
331
+ os.makedirs(folder_path, exist_ok=True)
332
+
333
+ moved = move_files_safely(file_list, folder_path, dry_run)
334
+ results[date_str] = moved
335
+
336
+ return results
337
+
338
+
339
+ # Alias
340
+ organize_date = organize_by_date
341
+
342
+
343
+ def organize_by_size(
344
+ directory: str,
345
+ size_ranges: Optional[Dict[str, tuple]] = None,
346
+ dry_run: bool = False
347
+ ) -> Dict[str, Dict[str, str]]:
348
+ """
349
+ Organize files by size into folders.
350
+
351
+ Alias: organize_size()
352
+
353
+ Args:
354
+ directory: Directory to organize
355
+ size_ranges: Custom size ranges in bytes
356
+ dry_run: Preview without organizing
357
+
358
+ Returns:
359
+ dict: Organization results
360
+
361
+ Examples:
362
+ >>> from ilovetools.automation import organize_size
363
+
364
+ >>> result = organize_size('/path/to/files')
365
+ >>> print(result.keys())
366
+ dict_keys(['Small', 'Medium', 'Large', 'Huge'])
367
+ """
368
+ if not os.path.exists(directory):
369
+ raise ValueError(f"Directory does not exist: {directory}")
370
+
371
+ # Default size ranges (in bytes)
372
+ if size_ranges is None:
373
+ size_ranges = {
374
+ 'Small': (0, 1024 * 1024), # 0-1MB
375
+ 'Medium': (1024 * 1024, 10 * 1024 * 1024), # 1-10MB
376
+ 'Large': (10 * 1024 * 1024, 100 * 1024 * 1024), # 10-100MB
377
+ 'Huge': (100 * 1024 * 1024, float('inf')) # 100MB+
378
+ }
379
+
380
+ # Scan files
381
+ files = []
382
+ for item in os.listdir(directory):
383
+ filepath = os.path.join(directory, item)
384
+ if os.path.isfile(filepath):
385
+ files.append(filepath)
386
+
387
+ # Group by size
388
+ size_groups = {category: [] for category in size_ranges.keys()}
389
+
390
+ for filepath in files:
391
+ file_size = os.path.getsize(filepath)
392
+
393
+ for category, (min_size, max_size) in size_ranges.items():
394
+ if min_size <= file_size < max_size:
395
+ size_groups[category].append(filepath)
396
+ break
397
+
398
+ # Create folders and move files
399
+ results = {}
400
+ for category, file_list in size_groups.items():
401
+ if file_list:
402
+ folder_path = os.path.join(directory, category)
403
+
404
+ if not dry_run:
405
+ os.makedirs(folder_path, exist_ok=True)
406
+
407
+ moved = move_files_safely(file_list, folder_path, dry_run)
408
+ results[category] = moved
409
+
410
+ return results
411
+
412
+
413
+ # Alias
414
+ organize_size = organize_by_size
415
+
416
+
417
+ def organize_by_name_pattern(
418
+ directory: str,
419
+ patterns: Dict[str, Callable[[str], bool]],
420
+ dry_run: bool = False
421
+ ) -> Dict[str, Dict[str, str]]:
422
+ """
423
+ Organize files by name patterns.
424
+
425
+ Alias: organize_pattern()
426
+
427
+ Args:
428
+ directory: Directory to organize
429
+ patterns: Dict of folder_name -> pattern_function
430
+ dry_run: Preview without organizing
431
+
432
+ Returns:
433
+ dict: Organization results
434
+
435
+ Examples:
436
+ >>> from ilovetools.automation import organize_pattern
437
+
438
+ >>> patterns = {
439
+ ... 'Work': lambda name: 'work' in name.lower(),
440
+ ... 'Personal': lambda name: 'personal' in name.lower(),
441
+ ... }
442
+ >>> result = organize_pattern('/path/to/files', patterns)
443
+ """
444
+ if not os.path.exists(directory):
445
+ raise ValueError(f"Directory does not exist: {directory}")
446
+
447
+ # Scan files
448
+ files = []
449
+ for item in os.listdir(directory):
450
+ filepath = os.path.join(directory, item)
451
+ if os.path.isfile(filepath):
452
+ files.append(filepath)
453
+
454
+ # Group by pattern
455
+ pattern_groups = {category: [] for category in patterns.keys()}
456
+ pattern_groups['Unmatched'] = []
457
+
458
+ for filepath in files:
459
+ filename = os.path.basename(filepath)
460
+ matched = False
461
+
462
+ for category, pattern_func in patterns.items():
463
+ if pattern_func(filename):
464
+ pattern_groups[category].append(filepath)
465
+ matched = True
466
+ break
467
+
468
+ if not matched:
469
+ pattern_groups['Unmatched'].append(filepath)
470
+
471
+ # Create folders and move files
472
+ results = {}
473
+ for category, file_list in pattern_groups.items():
474
+ if file_list:
475
+ folder_path = os.path.join(directory, category)
476
+
477
+ if not dry_run:
478
+ os.makedirs(folder_path, exist_ok=True)
479
+
480
+ moved = move_files_safely(file_list, folder_path, dry_run)
481
+ results[category] = moved
482
+
483
+ return results
484
+
485
+
486
+ # Alias
487
+ organize_pattern = organize_by_name_pattern
488
+
489
+
490
+ def undo_organization(
491
+ organization_result: Dict[str, Dict[str, str]],
492
+ dry_run: bool = False
493
+ ) -> Dict[str, str]:
494
+ """
495
+ Undo file organization by moving files back.
496
+
497
+ Args:
498
+ organization_result: Result from organize functions
499
+ dry_run: Preview without undoing
500
+
501
+ Returns:
502
+ dict: Restored file mappings
503
+
504
+ Examples:
505
+ >>> from ilovetools.automation import organize_ext, undo_organization
506
+
507
+ >>> result = organize_ext('/path/to/files')
508
+ >>> # Undo if needed
509
+ >>> restored = undo_organization(result)
510
+ """
511
+ restored = {}
512
+
513
+ for category, file_mappings in organization_result.items():
514
+ for old_path, new_path in file_mappings.items():
515
+ if os.path.exists(new_path):
516
+ restored[new_path] = old_path
517
+
518
+ if not dry_run:
519
+ # Create parent directory if needed
520
+ os.makedirs(os.path.dirname(old_path), exist_ok=True)
521
+ shutil.move(new_path, old_path)
522
+
523
+ return restored
@@ -0,0 +1,41 @@
1
+ """
2
+ Format conversion utilities
3
+ """
4
+
5
+ from .config_converter import (
6
+ json_to_yaml,
7
+ json_to_toml,
8
+ json_to_xml,
9
+ json_to_ini,
10
+ yaml_to_json,
11
+ yaml_to_dict,
12
+ dict_to_yaml,
13
+ toml_to_json,
14
+ toml_to_dict,
15
+ dict_to_toml,
16
+ xml_to_json,
17
+ ini_to_json,
18
+ validate_json,
19
+ validate_yaml,
20
+ minify_json,
21
+ prettify_json,
22
+ )
23
+
24
+ __all__ = [
25
+ 'json_to_yaml',
26
+ 'json_to_toml',
27
+ 'json_to_xml',
28
+ 'json_to_ini',
29
+ 'yaml_to_json',
30
+ 'yaml_to_dict',
31
+ 'dict_to_yaml',
32
+ 'toml_to_json',
33
+ 'toml_to_dict',
34
+ 'dict_to_toml',
35
+ 'xml_to_json',
36
+ 'ini_to_json',
37
+ 'validate_json',
38
+ 'validate_yaml',
39
+ 'minify_json',
40
+ 'prettify_json',
41
+ ]