github m3trik/pythontk v0.8.72
pythontk v0.8.72

4 hours ago
  • FileUtils.is_cloud_placeholder + FileUtils.free_space — cloud/space-aware primitives for diagnosing unreadable files (2026-06-27). Two zero-dependency, Windows-aware helpers. is_cloud_placeholder(path) returns True for a “dehydrated” cloud placeholder (OneDrive / Dropbox / Google Drive / Nextcloud) — it satisfies os.path.isfile/os.stat (size/mtime from placeholder metadata) but its bytes live in the cloud; reads the Windows st_file_attributes bitmask (OFFLINE / RECALL_ON_OPEN / RECALL_ON_DATA_ACCESS), never triggers a recall, False on non-Windows or any stat failure. It is detection, not diagnosis: a recall usually succeeds on demand, so a True result only means “cloud-managed, the sync client is relevant” — it does not imply the file is unreadable. free_space(path) returns the free bytes on the volume holding path (resolving up to the nearest existing ancestor, so it works on a file, a dir, or a not-yet-created child) via shutil.disk_usage, or None when no ancestor resolves; reads volume metadata only (safe on a placeholder). Together they turn an opaque OSError into a checkable cause — a (nearly) full volume, a common real reason an open() fails after isfile passed (a cloud file can’t land bytes with no room) — rather than guessing the placeholder state itself. Motivated by mayatk’s Shot Manifest, which previously mis-reported a stranded Dropbox CSV with confidently-wrong advice (“make it available offline”) when the real cause was a full partition (see mayatk CHANGELOG 2026-06-27). Tests: test_file.py::FileTest (+8: placeholder online-only / legacy-OFFLINE → True, local / POSIX-no-field / missing → False; free_space int for an existing dir, resolves a nonexistent child, None when unresolvable).
  • LoggingMixinsetLevel now re-enables custom levels after a level change (2026-06-27). Fixed a latent bug where lowering a logger's level would not re-enable the custom levels (SUCCESS/RESULT/NOTICE). These loggers are built via the Logger() constructor (not getLogger), so they are absent from manager.loggerDict; the stdlib setLevel's manager._clear_cache() therefore never touched their per-logger isEnabledFor cache. Once isEnabledFor(SUCCESS) was evaluated while the level was above SUCCESS (caching False), success() and the other custom levels stayed silently suppressed even after the level was lowered again. LoggerExt._set_level now clears self._cache directly. Surfaced by mayatk's scene_exporter promoting a per-task line to SUCCESS. Test: test_logging_mixin.py::LoggerExtTest::test_setlevel_clears_custom_level_cache; full module suite 55 green.

Don't miss a new pythontk release

NewReleases is sending notifications on new releases.