sy-python 0.2.0__cp38-abi3-manylinux_2_28_x86_64.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,30 @@
1
+ Metadata-Version: 2.4
2
+ Name: sy-python
3
+ Version: 0.2.0
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Intended Audience :: Developers
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Operating System :: MacOS
8
+ Classifier: Operating System :: POSIX :: Linux
9
+ Classifier: Operating System :: Microsoft :: Windows
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: Implementation :: CPython
17
+ Classifier: Programming Language :: Rust
18
+ Classifier: Topic :: System :: Archiving :: Backup
19
+ Classifier: Topic :: System :: Filesystems
20
+ Classifier: Typing :: Typed
21
+ Requires-Dist: pytest>=7.0 ; extra == 'dev'
22
+ Requires-Dist: tqdm>=4.0 ; extra == 'dev'
23
+ Provides-Extra: dev
24
+ Summary: Python bindings for sy - Modern file synchronization tool
25
+ Keywords: rsync,sync,file-transfer,backup
26
+ License: MIT
27
+ Requires-Python: >=3.8
28
+ Project-URL: Documentation, https://github.com/nijaru/sy#readme
29
+ Project-URL: Homepage, https://github.com/nijaru/sy
30
+ Project-URL: Repository, https://github.com/nijaru/sy
@@ -0,0 +1,12 @@
1
+ sy_python-0.2.0.dist-info/METADATA,sha256=YJoTuHqL-0RMkybFU-Simf37G47X-vvMayEahAr7gCk,1286
2
+ sy_python-0.2.0.dist-info/WHEEL,sha256=RkO9vuZebefxBO82xhdx_Vslv-lk-9t3-S9x5Fqg2yw,107
3
+ sy_python-0.2.0.dist-info/entry_points.txt,sha256=NPHeXCspWz0vGpS57shSO3ezGr5DOiByIM4ytzH_sJc,64
4
+ sypy/__init__.py,sha256=kUQ1kbnGgG15AhivJcHMjdIDjB0e8KD7za5xz4etnGg,2988
5
+ sypy/__main__.py,sha256=K9CZ6AJGxOFYSkuWRmvpm2bynZu1Ws_qDie_IPO8cjg,411
6
+ sypy/_sypy.abi3.so,sha256=1Qim8LWAipqsKs4e3ldWn9Ui_BHWDIreb_PUPiwOufw,20740713
7
+ sypy/_sypy.pyi,sha256=w12Ij8XV6p2f_XytXr-Wfk4YTwVWQSsEAPez3UWdUcs,13815
8
+ sypy/ls_types.py,sha256=PIm8Q9jEo-b5OaGxpJ4mcTgG4Dn4uXQHFvT9ARbiu7M,1299
9
+ sypy/py.typed,sha256=qww23I-O7yv_Kf5Wu2UW3r8K1Vd12UDESBl5tmzRSI0,60
10
+ sypy.libs/libcrypto-bfee2032.so.1.1,sha256=vENxnY50N4f5NMoJR5ElTBXei4_x6ZjNLP7oMzBioo8,3215921
11
+ sypy.libs/libssl-658e53cd.so.1.1,sha256=59sUdvtjU-6lBFU6e8nNeH96zgPwWQ9GIIuaOUUOASs,666857
12
+ sy_python-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.11.5)
3
+ Root-Is-Purelib: false
4
+ Tag: cp38-abi3-manylinux_2_28_x86_64
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ sy=sypy.__main__:main
3
+ sypy=sypy.__main__:main
sypy/__init__.py ADDED
@@ -0,0 +1,136 @@
1
+ """
2
+ sypy - Python bindings for sy file synchronization tool.
3
+
4
+ Fast, modern file synchronization with support for local, SSH, S3, and GCS.
5
+
6
+ Example:
7
+ >>> import sypy
8
+ >>> stats = sypy.sync("/source", "/dest")
9
+ >>> print(f"Synced {stats.files_created} files")
10
+
11
+ # With options
12
+ >>> stats = sypy.sync(
13
+ ... "/source", "/dest",
14
+ ... dry_run=True,
15
+ ... exclude=["*.log", "node_modules"],
16
+ ... )
17
+
18
+ # With S3 credentials
19
+ >>> s3 = sypy.S3Config(
20
+ ... access_key_id="...",
21
+ ... secret_access_key="...",
22
+ ... region="us-east-1",
23
+ ... )
24
+ >>> stats = sypy.sync("/local/", "s3://bucket/path/", s3=s3)
25
+
26
+ # With GCS credentials
27
+ >>> gcs = sypy.GcsConfig(credentials_file="/path/to/key.json")
28
+ >>> stats = sypy.sync("/local/", "gs://bucket/path/", gcs=gcs)
29
+
30
+ # With custom client options for high throughput
31
+ >>> options = sypy.CloudClientOptions.high_throughput()
32
+ >>> s3 = sypy.S3Config(..., client_options=options)
33
+ >>> stats = sypy.sync("/local/", "s3://bucket/", s3=s3, parallel=100)
34
+
35
+ # Dry-run with typed summary
36
+ >>> stats = sypy.sync("/source", "/dest", dry_run=True)
37
+ >>> summary = stats.dry_run_summary
38
+ >>> print(f"Would create {summary['would_create']['count']} files")
39
+
40
+ """
41
+
42
+ from typing import TypedDict
43
+
44
+
45
+ class DryRunChange(TypedDict):
46
+ """Details about changes that would be made"""
47
+
48
+ count: int
49
+ bytes: int
50
+
51
+
52
+ class DryRunSummary(TypedDict):
53
+ """Summary of what would happen in a dry-run"""
54
+
55
+ would_create: DryRunChange
56
+ would_update: DryRunChange
57
+ would_delete: DryRunChange
58
+ total_files: int
59
+ total_bytes: int
60
+
61
+
62
+ # Import TypedDict for ls functionality
63
+ from sypy._sypy import (
64
+ # Dry-run classes
65
+ ChangeAction,
66
+ # Client options
67
+ CloudClientOptions,
68
+ DirectoryChange,
69
+ DryRunDetails,
70
+ FileChange,
71
+ # Config classes
72
+ GcsConfig,
73
+ # List classes
74
+ ListEntry,
75
+ # Progress classes
76
+ ProgressSnapshot,
77
+ S3Config,
78
+ SshConfig,
79
+ SymlinkChange,
80
+ # Classes
81
+ SyncError,
82
+ SyncOptions,
83
+ SyncPath,
84
+ SyncStats,
85
+ # Version
86
+ __version__,
87
+ # Functions
88
+ ls,
89
+ # CLI functions
90
+ main,
91
+ parse_path,
92
+ run_daemon,
93
+ run_server,
94
+ sync,
95
+ sync_with_options,
96
+ )
97
+ from sypy.ls_types import ListEntryDict
98
+
99
+ __all__ = [
100
+ # Dry-run classes
101
+ "ChangeAction",
102
+ # Client options
103
+ "CloudClientOptions",
104
+ "DirectoryChange",
105
+ # TypedDicts
106
+ "DryRunChange",
107
+ "DryRunDetails",
108
+ "DryRunSummary",
109
+ "FileChange",
110
+ # Config classes
111
+ "GcsConfig",
112
+ # List classes
113
+ "ListEntry",
114
+ "ListEntryDict",
115
+ # Progress classes
116
+ "ProgressSnapshot",
117
+ "S3Config",
118
+ "SshConfig",
119
+ "SymlinkChange",
120
+ # Classes
121
+ "SyncError",
122
+ "SyncOptions",
123
+ "SyncPath",
124
+ "SyncStats",
125
+ # Version
126
+ "__version__",
127
+ # Functions
128
+ "ls",
129
+ # CLI functions
130
+ "main",
131
+ "parse_path",
132
+ "run_daemon",
133
+ "run_server",
134
+ "sync",
135
+ "sync_with_options",
136
+ ]
sypy/__main__.py ADDED
@@ -0,0 +1,21 @@
1
+ """
2
+ Entry point for `python -m sypy` command.
3
+
4
+ This allows running sy as a Python module:
5
+ python -m sypy /source /dest
6
+ python -m sypy --server /path
7
+ python -m sypy --daemon --socket ~/.sy/daemon.sock
8
+ """
9
+
10
+ import sys
11
+
12
+
13
+ def main() -> int:
14
+ """Main entry point for the sy CLI."""
15
+ from sypy._sypy import main as _main
16
+
17
+ return _main(sys.argv)
18
+
19
+
20
+ if __name__ == "__main__":
21
+ sys.exit(main())
sypy/_sypy.abi3.so ADDED
Binary file
sypy/_sypy.pyi ADDED
@@ -0,0 +1,521 @@
1
+ from collections.abc import Callable
2
+
3
+ __version__: str
4
+
5
+ class CloudClientOptions:
6
+ pool_max_idle_per_host: int
7
+ """Maximum idle connections per host. Default: 50."""
8
+
9
+ pool_idle_timeout_secs: int
10
+ """How long to keep idle connections (seconds). Default: 30."""
11
+
12
+ connect_timeout_secs: int
13
+ """Connection timeout (seconds). Default: 5."""
14
+
15
+ request_timeout_secs: int
16
+ """Request timeout including transfer (seconds). Default: 60."""
17
+
18
+ max_retries: int
19
+ """Maximum retry attempts. Default: 3."""
20
+
21
+ retry_timeout_secs: int
22
+ """Maximum time for retries (seconds). Default: 15."""
23
+
24
+ allow_http: bool
25
+ """Allow HTTP (non-TLS) connections. Default: False."""
26
+
27
+ def __init__(
28
+ self,
29
+ pool_max_idle_per_host: int = 50,
30
+ pool_idle_timeout_secs: int = 30,
31
+ connect_timeout_secs: int = 5,
32
+ request_timeout_secs: int = 60,
33
+ max_retries: int = 3,
34
+ retry_timeout_secs: int = 15,
35
+ allow_http: bool = False,
36
+ ) -> None: ...
37
+ @staticmethod
38
+ def high_throughput() -> CloudClientOptions: ...
39
+ @staticmethod
40
+ def low_latency() -> CloudClientOptions: ...
41
+
42
+ class S3Config:
43
+ access_key_id: str | None
44
+ """AWS access key ID."""
45
+
46
+ secret_access_key: str | None
47
+ """AWS secret access key."""
48
+
49
+ session_token: str | None
50
+ """AWS session token (for temporary credentials)."""
51
+
52
+ region: str | None
53
+ """AWS region (e.g., "us-east-1")."""
54
+
55
+ endpoint: str | None
56
+ """Custom endpoint URL for S3-compatible services."""
57
+
58
+ profile: str | None
59
+ """AWS profile name to use from ~/.aws/credentials."""
60
+
61
+ client_options: CloudClientOptions | None
62
+ """HTTP client options (timeouts, retries, connection pool)."""
63
+
64
+ def __init__(
65
+ self,
66
+ access_key_id: str | None = None,
67
+ secret_access_key: str | None = None,
68
+ session_token: str | None = None,
69
+ region: str | None = None,
70
+ endpoint: str | None = None,
71
+ profile: str | None = None,
72
+ client_options: CloudClientOptions | None = None,
73
+ ) -> None: ...
74
+
75
+ class GcsConfig:
76
+ credentials_file: str | None
77
+ """Path to service account JSON key file."""
78
+
79
+ project_id: str | None
80
+ """GCP project ID."""
81
+
82
+ credentials_json: str | None
83
+ """Service account JSON as a string (alternative to credentials_file)."""
84
+
85
+ client_options: CloudClientOptions | None
86
+ """HTTP client options (timeouts, retries, connection pool)."""
87
+
88
+ def __init__(
89
+ self,
90
+ credentials_file: str | None = None,
91
+ project_id: str | None = None,
92
+ credentials_json: str | None = None,
93
+ client_options: CloudClientOptions | None = None,
94
+ ) -> None: ...
95
+
96
+ class SshConfig:
97
+ key_file: str | None
98
+ """Path to private key file."""
99
+
100
+ port: int | None
101
+ """SSH port (default: 22)."""
102
+
103
+ password: str | None
104
+ """SSH password (usually not needed with key authentication)."""
105
+
106
+ compression: bool
107
+ """Enable compression for SSH connection."""
108
+
109
+ proxy_jump: str | None
110
+ """Proxy jump host (e.g., "bastion@proxy.example.com")."""
111
+
112
+ connect_timeout: int | None
113
+ """Connection timeout in seconds."""
114
+
115
+ pool_size: int | None
116
+ """Number of parallel SSH connections."""
117
+
118
+ def __init__(
119
+ self,
120
+ key_file: str | None = None,
121
+ port: int | None = None,
122
+ password: str | None = None,
123
+ compression: bool = False,
124
+ proxy_jump: str | None = None,
125
+ connect_timeout: int | None = None,
126
+ pool_size: int | None = None,
127
+ ) -> None: ...
128
+
129
+ class SyncError:
130
+ path: str
131
+ """Path that caused the error."""
132
+
133
+ error: str
134
+ """Error message."""
135
+
136
+ action: str
137
+ """Action that was being performed."""
138
+
139
+ class SyncStats:
140
+ files_scanned: int
141
+ """Number of files scanned."""
142
+
143
+ files_created: int
144
+ """Number of files created."""
145
+
146
+ files_updated: int
147
+ """Number of files updated."""
148
+
149
+ files_skipped: int
150
+ """Number of files skipped (already up-to-date)."""
151
+
152
+ files_deleted: int
153
+ """Number of files deleted."""
154
+
155
+ bytes_transferred: int
156
+ """Total bytes transferred."""
157
+
158
+ files_delta_synced: int
159
+ """Number of files synced using delta algorithm."""
160
+
161
+ delta_bytes_saved: int
162
+ """Bytes saved by delta sync."""
163
+
164
+ files_compressed: int
165
+ """Number of files compressed during transfer."""
166
+
167
+ compression_bytes_saved: int
168
+ """Bytes saved by compression."""
169
+
170
+ files_verified: int
171
+ """Number of files verified."""
172
+
173
+ verification_failures: int
174
+ """Number of verification failures."""
175
+
176
+ duration_secs: float
177
+ """Duration of the sync operation in seconds."""
178
+
179
+ bytes_would_add: int
180
+ """Bytes that would be added (dry-run only)."""
181
+
182
+ bytes_would_change: int
183
+ """Bytes that would change (dry-run only)."""
184
+
185
+ bytes_would_delete: int
186
+ """Bytes that would be deleted (dry-run only)."""
187
+
188
+ dirs_created: int
189
+ """Number of directories created."""
190
+
191
+ symlinks_created: int
192
+ """Number of symlinks created."""
193
+
194
+ @property
195
+ def errors(self) -> list[SyncError]: ...
196
+ @property
197
+ def success(self) -> bool: ...
198
+ @property
199
+ def transfer_rate(self) -> float: ...
200
+ @property
201
+ def dry_run_summary(self) -> dict[str, dict[str, int] | int]: ...
202
+
203
+ class ProgressSnapshot:
204
+ total_bytes: int
205
+ """Estimated total bytes to process (may be 0 if unknown)."""
206
+
207
+ bytes: int
208
+ """Bytes completed so far."""
209
+
210
+ bytes_per_sec: int
211
+ """Instantaneous speed in bytes per second."""
212
+
213
+ transfers: int
214
+ """Number of transfers (files) completed."""
215
+
216
+ total_transfers: int
217
+ """Total number of transfers planned."""
218
+
219
+ active_transfers: int
220
+ """Number of currently active (in-flight) transfers."""
221
+
222
+ percentage: float | None
223
+ """Percentage complete (0.0 to 100.0), None if total_bytes is 0/unknown."""
224
+
225
+ elapsed_secs: float
226
+ """Elapsed time in seconds since sync started."""
227
+
228
+ @property
229
+ def transferring(self) -> list[str]: ...
230
+ """List of currently transferring file paths."""
231
+
232
+ @property
233
+ def current_file(self) -> str | None: ...
234
+ """Current file being transferred (first in transferring list), or None."""
235
+
236
+ @property
237
+ def speed_human(self) -> str: ...
238
+ """Speed as a human-readable string (e.g., "10.5 MB/s")."""
239
+
240
+ @property
241
+ def bytes_human(self) -> str: ...
242
+ """Bytes as a human-readable string (e.g., "1.5 GB")."""
243
+
244
+ @property
245
+ def total_bytes_human(self) -> str: ...
246
+ """Total bytes as a human-readable string (e.g., "10.2 GB")."""
247
+
248
+ @property
249
+ def eta_secs(self) -> float | None: ...
250
+ """Estimated time remaining in seconds, or None if unknown."""
251
+
252
+ class SyncPath:
253
+ def __init__(self, path: str) -> None: ...
254
+ @property
255
+ def path(self) -> str: ...
256
+ @property
257
+ def is_local(self) -> bool: ...
258
+ @property
259
+ def is_remote(self) -> bool: ...
260
+ @property
261
+ def is_s3(self) -> bool: ...
262
+ @property
263
+ def is_gcs(self) -> bool: ...
264
+ @property
265
+ def is_daemon(self) -> bool: ...
266
+ @property
267
+ def has_trailing_slash(self) -> bool: ...
268
+ @property
269
+ def host(self) -> str | None: ...
270
+ @property
271
+ def user(self) -> str | None: ...
272
+ @property
273
+ def bucket(self) -> str | None: ...
274
+
275
+ class SyncOptions:
276
+ dry_run: bool
277
+ """Dry run mode - show changes without applying."""
278
+
279
+ delete: bool
280
+ """Delete files in destination not present in source."""
281
+
282
+ delete_threshold: int
283
+ """Maximum percentage of files that can be deleted (0-100)."""
284
+
285
+ trash: bool
286
+ """Move deleted files to trash instead of permanent deletion."""
287
+
288
+ force_delete: bool
289
+ """Skip deletion safety checks."""
290
+
291
+ parallel: int
292
+ """Number of parallel file transfers."""
293
+
294
+ max_errors: int
295
+ """Maximum number of errors before aborting (0 = unlimited)."""
296
+
297
+ min_size: str | None
298
+ """Minimum file size to sync (e.g., "1MB")."""
299
+
300
+ max_size: str | None
301
+ """Maximum file size to sync (e.g., "1GB")."""
302
+
303
+ exclude: list[str]
304
+ """Exclude patterns."""
305
+
306
+ include: list[str]
307
+ """Include patterns."""
308
+
309
+ bwlimit: str | None
310
+ """Bandwidth limit (e.g., "10MB")."""
311
+
312
+ resume: bool
313
+ """Enable resume support for interrupted transfers."""
314
+
315
+ verify: bool
316
+ """Verify file integrity after write."""
317
+
318
+ compress: bool
319
+ """Enable compression for network transfers."""
320
+
321
+ preserve_xattrs: bool
322
+ """Preserve extended attributes."""
323
+
324
+ preserve_hardlinks: bool
325
+ """Preserve hard links."""
326
+
327
+ preserve_acls: bool
328
+ """Preserve access control lists."""
329
+
330
+ preserve_permissions: bool
331
+ """Preserve permissions."""
332
+
333
+ preserve_times: bool
334
+ """Preserve modification times."""
335
+
336
+ ignore_times: bool
337
+ """Ignore modification times, always compare checksums."""
338
+
339
+ size_only: bool
340
+ """Only compare file size, skip mtime checks."""
341
+
342
+ checksum: bool
343
+ """Always compare checksums instead of size+mtime."""
344
+
345
+ update: bool
346
+ """Skip files where destination is newer."""
347
+
348
+ ignore_existing: bool
349
+ """Skip files that already exist in destination."""
350
+
351
+ gitignore: bool
352
+ """Apply .gitignore rules."""
353
+
354
+ exclude_vcs: bool
355
+ """Exclude .git directories."""
356
+
357
+ bidirectional: bool
358
+ """Bidirectional sync mode."""
359
+
360
+ conflict_resolve: str
361
+ """Conflict resolution strategy ("newer", "larger", "smaller", "source", "dest", "rename")."""
362
+
363
+ daemon_auto: bool
364
+ """Use daemon mode for fast repeated syncs."""
365
+
366
+ retry: int
367
+ """Maximum retry attempts for network operations."""
368
+
369
+ retry_delay: int
370
+ """Initial delay between retries in seconds."""
371
+
372
+ s3: S3Config | None
373
+ """S3 configuration for S3/S3-compatible storage."""
374
+
375
+ gcs: GcsConfig | None
376
+ """GCS configuration for Google Cloud Storage."""
377
+
378
+ ssh: SshConfig | None
379
+ """SSH configuration for remote connections."""
380
+
381
+ def __init__(
382
+ self,
383
+ dry_run: bool = False,
384
+ delete: bool = False,
385
+ delete_threshold: int = 50,
386
+ trash: bool = False,
387
+ force_delete: bool = False,
388
+ parallel: int = 10,
389
+ max_errors: int = 100,
390
+ min_size: str | None = None,
391
+ max_size: str | None = None,
392
+ exclude: list[str] | None = None,
393
+ include: list[str] | None = None,
394
+ bwlimit: str | None = None,
395
+ resume: bool = True,
396
+ verify: bool = False,
397
+ compress: bool = False,
398
+ preserve_xattrs: bool = False,
399
+ preserve_hardlinks: bool = False,
400
+ preserve_acls: bool = False,
401
+ preserve_permissions: bool = False,
402
+ preserve_times: bool = False,
403
+ ignore_times: bool = False,
404
+ size_only: bool = False,
405
+ checksum: bool = False,
406
+ update: bool = False,
407
+ ignore_existing: bool = False,
408
+ gitignore: bool = False,
409
+ exclude_vcs: bool = False,
410
+ bidirectional: bool = False,
411
+ conflict_resolve: str = "newer",
412
+ daemon_auto: bool = False,
413
+ retry: int = 3,
414
+ retry_delay: int = 1,
415
+ s3: S3Config | None = None,
416
+ gcs: GcsConfig | None = None,
417
+ ssh: SshConfig | None = None,
418
+ ) -> None: ...
419
+
420
+ # Type alias for progress callback
421
+ type ProgressCallback = Callable[[ProgressSnapshot], None]
422
+ """
423
+ Progress callback function signature.
424
+
425
+ Args:
426
+ snapshot: ProgressSnapshot describing current sync state
427
+ """
428
+
429
+ def sync(
430
+ source: str,
431
+ dest: str,
432
+ *,
433
+ dry_run: bool = False,
434
+ delete: bool = False,
435
+ delete_threshold: int = 50,
436
+ parallel: int = 10,
437
+ verify: bool = False,
438
+ compress: bool = False,
439
+ checksum: bool = False,
440
+ exclude: list[str] | None = None,
441
+ include: list[str] | None = None,
442
+ min_size: str | None = None,
443
+ max_size: str | None = None,
444
+ bwlimit: str | None = None,
445
+ progress_callback: ProgressCallback | None = None,
446
+ progress_frequency_ms: int = 1000,
447
+ daemon_auto: bool = False,
448
+ resume: bool = True,
449
+ ignore_times: bool = False,
450
+ size_only: bool = False,
451
+ update: bool = False,
452
+ ignore_existing: bool = False,
453
+ gitignore: bool = False,
454
+ exclude_vcs: bool = False,
455
+ preserve_xattrs: bool = False,
456
+ preserve_hardlinks: bool = False,
457
+ preserve_permissions: bool = False,
458
+ preserve_times: bool = False,
459
+ retry: int = 3,
460
+ retry_delay: int = 1,
461
+ s3: S3Config | None = None,
462
+ gcs: GcsConfig | None = None,
463
+ ssh: SshConfig | None = None,
464
+ ) -> SyncStats: ...
465
+ def sync_with_options(
466
+ source: str,
467
+ dest: str,
468
+ options: SyncOptions,
469
+ progress_callback: ProgressCallback | None = None,
470
+ progress_frequency_ms: int = 1000,
471
+ ) -> SyncStats: ...
472
+ def parse_path(path: str) -> SyncPath: ...
473
+
474
+ class ListEntry:
475
+ path: str
476
+ """Relative path of the entry."""
477
+
478
+ size: int
479
+ """File size in bytes (0 for directories)."""
480
+
481
+ mod_time: str
482
+ """Modification time in RFC3339 format."""
483
+
484
+ is_dir: bool
485
+ """Whether this is a directory."""
486
+
487
+ entry_type: str
488
+ """Entry type: "file", "directory", or "symlink"."""
489
+
490
+ mime_type: str | None
491
+ """MIME type (inferred from extension)."""
492
+
493
+ symlink_target: str | None
494
+ """Symlink target path (if this is a symlink)."""
495
+
496
+ is_sparse: bool | None
497
+ """Whether this is a sparse file."""
498
+
499
+ allocated_size: int | None
500
+ """Actual allocated size on disk (may differ from size for sparse files)."""
501
+
502
+ inode: int | None
503
+ """Inode number (Unix only)."""
504
+
505
+ num_links: int | None
506
+ """Number of hard links to this file."""
507
+
508
+ def to_dict(self) -> dict[str, str | int | bool | None]: ...
509
+
510
+ def ls(
511
+ path: str,
512
+ recursive: bool = False,
513
+ max_depth: int | None = None,
514
+ files_only: bool = False,
515
+ dirs_only: bool = False,
516
+ ) -> list[ListEntry]: ...
517
+
518
+ # CLI functions
519
+ def main(args: list[str] | None = None) -> int: ...
520
+ def run_server(path: str) -> None: ...
521
+ def run_daemon(socket_path: str, root_path: str | None = None) -> None: ...
sypy/ls_types.py ADDED
@@ -0,0 +1,55 @@
1
+ """
2
+ TypedDict definitions for sy-ls functionality.
3
+
4
+ This module provides TypedDict types for type-safe usage of the ls() function
5
+ and ListEntry objects.
6
+ """
7
+
8
+ from typing import TypedDict
9
+
10
+
11
+ class ListEntryDict(TypedDict, total=False):
12
+ """
13
+ TypedDict representing a directory listing entry.
14
+
15
+ All fields are required except those marked Optional.
16
+ Use this for type hints when calling entry.to_dict().
17
+
18
+ Example:
19
+ >>> entries = sypy.ls("/path")
20
+ >>> dicts: list[ListEntryDict] = [e.to_dict() for e in entries]
21
+
22
+ """
23
+
24
+ path: str
25
+ """Relative path of the entry."""
26
+
27
+ size: int
28
+ """File size in bytes (0 for directories)."""
29
+
30
+ mod_time: str
31
+ """Modification time in RFC3339 format."""
32
+
33
+ is_dir: bool
34
+ """Whether this is a directory."""
35
+
36
+ entry_type: str
37
+ """Entry type: "file", "directory", or "symlink"."""
38
+
39
+ mime_type: str | None
40
+ """MIME type (inferred from extension)."""
41
+
42
+ symlink_target: str | None
43
+ """Symlink target path (if this is a symlink)."""
44
+
45
+ is_sparse: bool | None
46
+ """Whether this is a sparse file."""
47
+
48
+ allocated_size: int | None
49
+ """Actual allocated size on disk."""
50
+
51
+ inode: int | None
52
+ """Inode number (Unix only)."""
53
+
54
+ num_links: int | None
55
+ """Number of hard links to this file."""
sypy/py.typed ADDED
@@ -0,0 +1 @@
1
+ # PEP 561 marker file - this package supports type checking
Binary file
Binary file