zerofilesystem 0.1.0__py3-none-any.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.
@@ -0,0 +1,326 @@
1
+ """zerofilesystem - Cross-platform file system utilities.
2
+
3
+ Usage:
4
+ import zerofilesystem as zo
5
+
6
+ # Read/write files
7
+ zo.write_text("file.txt", "Hello World")
8
+ content = zo.read_text("file.txt")
9
+
10
+ # JSON operations
11
+ zo.write_json("data.json", {"key": "value"})
12
+ data = zo.read_json("data.json")
13
+
14
+ # Find files
15
+ py_files = zo.find_files(".", pattern="**/*.py")
16
+
17
+ # File locking
18
+ with zo.FileLock("/tmp/my.lock"):
19
+ # Critical section
20
+ pass
21
+
22
+ # Transactions
23
+ with zo.FileTransaction() as tx:
24
+ tx.write_text("file1.txt", "content1")
25
+ tx.write_text("file2.txt", "content2")
26
+
27
+ # Archives
28
+ zo.create_zip("./src", "backup.zip")
29
+ zo.extract("backup.zip", "./extracted")
30
+
31
+ Copyright (c) 2025 Francesco Favi
32
+ License: MIT
33
+ """
34
+
35
+ from zerofilesystem._platform import IS_LINUX, IS_MACOS, IS_UNIX, IS_WINDOWS, Pathish
36
+ from zerofilesystem.classes import (
37
+ ArchiveError,
38
+ ArchiveHandler,
39
+ DirectoryOps,
40
+ EventType,
41
+ FileCleaner,
42
+ FileFinder,
43
+ FileHasher,
44
+ FileIO,
45
+ FileLock,
46
+ FileLockedError,
47
+ FileMeta,
48
+ FilePermissions,
49
+ FileSync,
50
+ FileTransaction,
51
+ FileUtils,
52
+ FileWatcher,
53
+ Finder,
54
+ GzipHandler,
55
+ HashMismatchError,
56
+ IntegrityChecker,
57
+ IntegrityError,
58
+ InvalidPathError,
59
+ JsonHandler,
60
+ PathUtils,
61
+ PermissionDeniedError,
62
+ SecureDeleteError,
63
+ SecureOps,
64
+ SyncError,
65
+ TransactionError,
66
+ Watcher,
67
+ WatchEvent,
68
+ ZeroOSError,
69
+ )
70
+ from zerofilesystem.zerofilesystem import ZeroOS
71
+
72
+ __version__ = "0.1.0"
73
+ __author__ = "Francesco Favi"
74
+ __email__ = "14098835+francescofavi@users.noreply.github.com"
75
+
76
+ # =============================================================================
77
+ # BASIC I/O
78
+ # =============================================================================
79
+
80
+ read_text = FileIO.read_text
81
+ write_text = FileIO.write_text
82
+ read_bytes = FileIO.read_bytes
83
+ write_bytes = FileIO.write_bytes
84
+
85
+ # =============================================================================
86
+ # JSON
87
+ # =============================================================================
88
+
89
+ read_json = JsonHandler.read_json
90
+ write_json = JsonHandler.write_json
91
+
92
+ # =============================================================================
93
+ # GZIP
94
+ # =============================================================================
95
+
96
+ gzip_compress = GzipHandler.compress
97
+ gzip_decompress = GzipHandler.decompress
98
+
99
+ # =============================================================================
100
+ # DISCOVERY
101
+ # =============================================================================
102
+
103
+ find_files = FileFinder.find_files
104
+ walk_files = FileFinder.walk_files
105
+ is_hidden = FileFinder.is_hidden
106
+
107
+ # =============================================================================
108
+ # CLEANUP
109
+ # =============================================================================
110
+
111
+ delete_files = FileCleaner.delete_files
112
+ delete_empty_dirs = FileCleaner.delete_empty_dirs
113
+
114
+ # =============================================================================
115
+ # SYNC
116
+ # =============================================================================
117
+
118
+ move_if_absent = FileSync.move_if_absent
119
+ copy_if_newer = FileSync.copy_if_newer
120
+
121
+ # =============================================================================
122
+ # HASH
123
+ # =============================================================================
124
+
125
+ file_hash = FileHasher.file_hash
126
+
127
+ # =============================================================================
128
+ # META
129
+ # =============================================================================
130
+
131
+ ensure_dir = FileMeta.ensure_dir
132
+ touch = FileMeta.touch
133
+ file_size = FileMeta.file_size
134
+ disk_usage = FileMeta.disk_usage
135
+
136
+ # =============================================================================
137
+ # UTILS
138
+ # =============================================================================
139
+
140
+ safe_filename = FileUtils.safe_filename
141
+ atomic_write = FileUtils.atomic_write
142
+
143
+ # =============================================================================
144
+ # PATH UTILS
145
+ # =============================================================================
146
+
147
+ normalize_path = PathUtils.normalize
148
+ to_absolute = PathUtils.to_absolute
149
+ to_relative = PathUtils.to_relative
150
+ to_posix = PathUtils.to_posix
151
+ expand_path = PathUtils.expand
152
+ is_subpath = PathUtils.is_subpath
153
+ common_path = PathUtils.common_path
154
+ validate_path = PathUtils.validate_path
155
+
156
+ # =============================================================================
157
+ # PERMISSIONS
158
+ # =============================================================================
159
+
160
+ get_metadata = FilePermissions.get_metadata
161
+ set_readonly = FilePermissions.set_readonly
162
+ set_hidden = FilePermissions.set_hidden
163
+ set_executable = FilePermissions.set_executable
164
+ set_permissions = FilePermissions.set_permissions
165
+ copy_permissions = FilePermissions.copy_permissions
166
+ set_timestamps = FilePermissions.set_timestamps
167
+ mode_to_string = FilePermissions.mode_to_string
168
+ string_to_mode = FilePermissions.string_to_mode
169
+
170
+ # =============================================================================
171
+ # DIRECTORY OPS
172
+ # =============================================================================
173
+
174
+ copy_tree = DirectoryOps.copy_tree
175
+ move_tree = DirectoryOps.move_tree
176
+ sync_dirs = DirectoryOps.sync
177
+ temp_directory = DirectoryOps.temp_directory
178
+ tree_size = DirectoryOps.tree_size
179
+ tree_file_count = DirectoryOps.tree_file_count
180
+ flatten_tree = DirectoryOps.flatten
181
+
182
+ # =============================================================================
183
+ # INTEGRITY
184
+ # =============================================================================
185
+
186
+ directory_hash = IntegrityChecker.directory_hash
187
+ create_manifest = IntegrityChecker.create_manifest
188
+ save_manifest = IntegrityChecker.save_manifest
189
+ load_manifest = IntegrityChecker.load_manifest
190
+ verify_manifest = IntegrityChecker.verify_manifest
191
+ verify_file = IntegrityChecker.verify_file
192
+ compare_directories = IntegrityChecker.compare_directories
193
+ snapshot_hash = IntegrityChecker.snapshot_hash
194
+
195
+ # =============================================================================
196
+ # SECURE
197
+ # =============================================================================
198
+
199
+ secure_delete = SecureOps.secure_delete
200
+ secure_delete_directory = SecureOps.secure_delete_directory
201
+ private_directory = SecureOps.private_directory
202
+ create_private_file = SecureOps.create_private_file
203
+
204
+ # =============================================================================
205
+ # ARCHIVE
206
+ # =============================================================================
207
+
208
+ create_tar = ArchiveHandler.create_tar
209
+ create_zip = ArchiveHandler.create_zip
210
+ extract_tar = ArchiveHandler.extract_tar
211
+ extract_zip = ArchiveHandler.extract_zip
212
+ extract = ArchiveHandler.extract
213
+ list_archive = ArchiveHandler.list_archive
214
+
215
+ # =============================================================================
216
+ # __all__
217
+ # =============================================================================
218
+
219
+ __all__ = [
220
+ # Facade class
221
+ "ZeroOS",
222
+ # Platform constants
223
+ "IS_WINDOWS",
224
+ "IS_MACOS",
225
+ "IS_LINUX",
226
+ "IS_UNIX",
227
+ "Pathish",
228
+ # Classes (for advanced usage)
229
+ "Finder",
230
+ "Watcher",
231
+ "WatchEvent",
232
+ "EventType",
233
+ "FileLock",
234
+ "FileTransaction",
235
+ "FileWatcher", # Legacy
236
+ # Exceptions
237
+ "ZeroOSError",
238
+ "FileLockedError",
239
+ "InvalidPathError",
240
+ "HashMismatchError",
241
+ "IntegrityError",
242
+ "TransactionError",
243
+ "ArchiveError",
244
+ "PermissionDeniedError",
245
+ "SecureDeleteError",
246
+ "SyncError",
247
+ # Basic I/O
248
+ "read_text",
249
+ "write_text",
250
+ "read_bytes",
251
+ "write_bytes",
252
+ # JSON
253
+ "read_json",
254
+ "write_json",
255
+ # Gzip
256
+ "gzip_compress",
257
+ "gzip_decompress",
258
+ # Discovery
259
+ "find_files",
260
+ "walk_files",
261
+ "is_hidden",
262
+ # Cleanup
263
+ "delete_files",
264
+ "delete_empty_dirs",
265
+ # Sync
266
+ "move_if_absent",
267
+ "copy_if_newer",
268
+ # Hash
269
+ "file_hash",
270
+ # Meta
271
+ "ensure_dir",
272
+ "touch",
273
+ "file_size",
274
+ "disk_usage",
275
+ # Utils
276
+ "safe_filename",
277
+ "atomic_write",
278
+ # Path utils
279
+ "normalize_path",
280
+ "to_absolute",
281
+ "to_relative",
282
+ "to_posix",
283
+ "expand_path",
284
+ "is_subpath",
285
+ "common_path",
286
+ "validate_path",
287
+ # Permissions
288
+ "get_metadata",
289
+ "set_readonly",
290
+ "set_hidden",
291
+ "set_executable",
292
+ "set_permissions",
293
+ "copy_permissions",
294
+ "set_timestamps",
295
+ "mode_to_string",
296
+ "string_to_mode",
297
+ # Directory ops
298
+ "copy_tree",
299
+ "move_tree",
300
+ "sync_dirs",
301
+ "temp_directory",
302
+ "tree_size",
303
+ "tree_file_count",
304
+ "flatten_tree",
305
+ # Integrity
306
+ "directory_hash",
307
+ "create_manifest",
308
+ "save_manifest",
309
+ "load_manifest",
310
+ "verify_manifest",
311
+ "verify_file",
312
+ "compare_directories",
313
+ "snapshot_hash",
314
+ # Secure
315
+ "secure_delete",
316
+ "secure_delete_directory",
317
+ "private_directory",
318
+ "create_private_file",
319
+ # Archive
320
+ "create_tar",
321
+ "create_zip",
322
+ "extract_tar",
323
+ "extract_zip",
324
+ "extract",
325
+ "list_archive",
326
+ ]
@@ -0,0 +1,13 @@
1
+ """Platform detection constants and shared types."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ IS_WINDOWS: bool = sys.platform == "win32"
9
+ IS_MACOS: bool = sys.platform == "darwin"
10
+ IS_LINUX: bool = sys.platform.startswith("linux")
11
+ IS_UNIX: bool = IS_MACOS or IS_LINUX
12
+
13
+ Pathish = str | Path
@@ -0,0 +1,84 @@
1
+ """Helper classes for file operations."""
2
+
3
+ from zerofilesystem.classes.archive_handler import ArchiveHandler
4
+ from zerofilesystem.classes.directory_ops import DirectoryOps
5
+ from zerofilesystem.classes.exceptions import (
6
+ ArchiveError,
7
+ FileLockedError,
8
+ HashMismatchError,
9
+ IntegrityError,
10
+ InvalidPathError,
11
+ PermissionDeniedError,
12
+ SecureDeleteError,
13
+ SyncError,
14
+ TransactionError,
15
+ ZeroOSError,
16
+ )
17
+ from zerofilesystem.classes.file_lock import FileLock
18
+ from zerofilesystem.classes.file_permissions import FilePermissions
19
+ from zerofilesystem.classes.file_transaction import FileTransaction
20
+ from zerofilesystem.classes.files import FileCleaner, FileFinder, FileHasher, FileMeta, FileSync
21
+ from zerofilesystem.classes.finder import Finder
22
+ from zerofilesystem.classes.integrity_checker import IntegrityChecker
23
+ from zerofilesystem.classes.io import FileIO, FileUtils, GzipHandler, JsonHandler
24
+ from zerofilesystem.classes.path_utils import PathUtils
25
+ from zerofilesystem.classes.secure_ops import SecureOps
26
+ from zerofilesystem.classes.watcher import (
27
+ EventType,
28
+ FileWatcher,
29
+ Watcher,
30
+ WatchEvent,
31
+ WatchEventType,
32
+ )
33
+
34
+ # Legacy alias
35
+ WatchEventOld = WatchEvent
36
+
37
+ __all__ = [
38
+ # Core I/O
39
+ "FileIO",
40
+ "JsonHandler",
41
+ "GzipHandler",
42
+ "FileUtils",
43
+ # Discovery and cleanup
44
+ "Finder",
45
+ "FileFinder",
46
+ "FileCleaner",
47
+ # Sync and file operations
48
+ "FileSync",
49
+ "FileHasher",
50
+ "FileMeta",
51
+ "FileLock",
52
+ # Path utilities
53
+ "PathUtils",
54
+ # Permissions and metadata
55
+ "FilePermissions",
56
+ # Directory operations
57
+ "DirectoryOps",
58
+ # Integrity verification
59
+ "IntegrityChecker",
60
+ # Transactions
61
+ "FileTransaction",
62
+ # Security
63
+ "SecureOps",
64
+ # Archives
65
+ "ArchiveHandler",
66
+ # File watching
67
+ "Watcher",
68
+ "WatchEvent",
69
+ "EventType",
70
+ "FileWatcher", # Legacy
71
+ "WatchEventType", # Legacy alias
72
+ "WatchEventOld", # Legacy alias
73
+ # Exceptions
74
+ "ZeroOSError",
75
+ "FileLockedError",
76
+ "InvalidPathError",
77
+ "HashMismatchError",
78
+ "IntegrityError",
79
+ "TransactionError",
80
+ "ArchiveError",
81
+ "PermissionDeniedError",
82
+ "SecureDeleteError",
83
+ "SyncError",
84
+ ]
@@ -0,0 +1,107 @@
1
+ """Shared internal utilities for zerofilesystem classes.
2
+
3
+ Not part of the public API. Used by finder.py, watcher.py, and other modules
4
+ to avoid code duplication.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import re
11
+ from datetime import datetime, timedelta
12
+ from pathlib import Path
13
+
14
+ from zerofilesystem._platform import IS_WINDOWS
15
+
16
+ # =============================================================================
17
+ # SHARED CONSTANTS
18
+ # =============================================================================
19
+
20
+ FILE_ATTRIBUTE_HIDDEN: int = 0x2
21
+ FILE_ATTRIBUTE_READONLY: int = 0x1
22
+
23
+ MAX_RENAME_CONFLICTS: int = 10000
24
+
25
+ HASH_CHUNK_SIZE: int = 1024 * 1024 # 1 MB
26
+
27
+ # Size unit multipliers (bytes)
28
+ SIZE_UNITS: dict[str, int] = {
29
+ "B": 1,
30
+ "KB": 1024,
31
+ "MB": 1024 * 1024,
32
+ "GB": 1024 * 1024 * 1024,
33
+ "TB": 1024 * 1024 * 1024 * 1024,
34
+ "K": 1024,
35
+ "M": 1024 * 1024,
36
+ "G": 1024 * 1024 * 1024,
37
+ "T": 1024 * 1024 * 1024 * 1024,
38
+ }
39
+
40
+
41
+ # =============================================================================
42
+ # SHARED FUNCTIONS
43
+ # =============================================================================
44
+
45
+
46
+ def parse_size(size: int | str) -> int:
47
+ """Parse size string like '1KB', '5MB', '1.5GB' to bytes."""
48
+ if isinstance(size, int):
49
+ return size
50
+
51
+ size = size.strip().upper()
52
+
53
+ match = re.match(r"^([\d.]+)\s*([A-Z]*B?)$", size)
54
+ if not match:
55
+ raise ValueError(f"Invalid size format: {size}")
56
+
57
+ value = float(match.group(1))
58
+ unit = match.group(2) or "B"
59
+
60
+ if unit not in SIZE_UNITS:
61
+ raise ValueError(f"Unknown size unit: {unit}")
62
+
63
+ return int(value * SIZE_UNITS[unit])
64
+
65
+
66
+ def parse_datetime(dt: datetime | str | timedelta) -> datetime:
67
+ """Parse datetime from various formats."""
68
+ if isinstance(dt, datetime):
69
+ return dt
70
+
71
+ if isinstance(dt, timedelta):
72
+ return datetime.now() - dt
73
+
74
+ dt_str = dt.strip()
75
+
76
+ formats = [
77
+ "%Y-%m-%d %H:%M:%S",
78
+ "%Y-%m-%d %H:%M",
79
+ "%Y-%m-%d",
80
+ "%Y/%m/%d %H:%M:%S",
81
+ "%Y/%m/%d",
82
+ "%d-%m-%Y",
83
+ "%d/%m/%Y",
84
+ ]
85
+
86
+ for fmt in formats:
87
+ try:
88
+ return datetime.strptime(dt_str, fmt)
89
+ except ValueError:
90
+ continue
91
+
92
+ raise ValueError(f"Cannot parse datetime: {dt}")
93
+
94
+
95
+ def is_hidden(path: Path) -> bool:
96
+ """Check if file is hidden (cross-platform)."""
97
+ if path.name.startswith("."):
98
+ return True
99
+
100
+ if IS_WINDOWS:
101
+ try:
102
+ attrs = os.stat(path).st_file_attributes # type: ignore[attr-defined]
103
+ return bool(attrs & FILE_ATTRIBUTE_HIDDEN)
104
+ except (AttributeError, OSError):
105
+ return False
106
+
107
+ return False