📰 Treestamps News¶
v5.2.0¶
-
Features
- New read-only
Treestamps.inspect()andGrovestamps.inspect()report on stamp files without loading them: presence, age, entries, a leftover WAL, and the config keys that would discard each one, optionally for child stamp files too.
- New read-only
v5.1.1¶
-
Fixes
- Importing treestamps works on Python 3.11. A config field default that only Python 3.12 and later accept raised
ValueErrorat import, so 5.0.0 through 5.1.0 could not run on 3.11.
- Importing treestamps works on Python 3.11. A config field default that only Python 3.12 and later accept raised
v5.1.0¶
-
Changes
- Require Python 3.11.
Grovestamps.load()now raisesAssertionErrorwhen passed ayamlargument that is not aMapping,str,bytes, orPath. Previously it was silently ignored.
v5.0.1¶
Fixes¶
- A snapshot discarded for a
check_configmismatch is now rewritten with the current config on the nextdumpf(), even by a run that sets no file timestamps. Previously such a run left the rejected file on disk unchanged, so the mismatch warning repeated on every subsequent run.
v5.0.0¶
Features¶
- New
program_config_defaultsconfig option. When set, missing keys are filled from it on both sides before comparing, so a program that adds or retires a recorded config key no longer invalidates stamp files written before the change. Only keys whose values actually differ invalidate. Defaults are not filtered byprogram_config_keys, so retired keys may keep a default. - New
noteconfig option: extra comment lines for the header that now leads every generated snapshot and WAL file. The header names the writing program and states that the file is machine-written and not a config file. Comments are invisible to the loader, so they never affect comparison. - New
program_config_key_labelsconfig option maps internal config key names to human readable names in config mismatch warnings. - New
dir_config_fingerprint()helper hashes the parsed, canonicalized values of per-directory config files below a tree root. Fold it into aprogram_configso per-directory config edits invalidate their tree. Comment, whitespace, and key-order edits do not change the digest; option value edits, adds, removes, and renames do. - New
GrovestampsConfig.tree_config_factorybuilds aTreestampsConfigper top path, so each tree can record its own resolved program config. ReturningNoneskips that tree entirely: no store and no stamp file.
Changes¶
- The
treestamps_configyaml block is no longer written or compared. It duplicatedignoreandsymlinks, which programs whose file selection depends on them already record inprogram_config. The tag is still popped when loading, so files written by earlier versions load normally. A program that relied on it must add those keys toprogram_config_keys. TreestampsConfig.get_config_dict()is removed.GrovestampsConfiggained fields, which shifts the position ofpathsfor positional construction. Construct configs with keyword arguments.
Migration¶
- Upgrading invalidates nothing: the removed block is ignored, and the
configblock is unchanged. - Trees processed alternately by 5.0.0 and older versions re-optimize once per version switch, because older versions compare a block 5.0.0 no longer writes. Pin one version per shared tree, or run once with
check_config=False.
v4.1.1¶
-
Fixes
- Stamps discarded because of a
check_configmismatch now log a warning naming the stamp file and the specific differing config keys, instead of being silently dropped.
- Stamps discarded because of a
v4.1.0¶
-
Fixes
- Fix WAL data loss:
dumps()anddump_dict()closed the WAL, so the nextset()truncated the on-disk WAL, destroying entries not yet in a snapshot. - Fix
Grovestampscreated with relative paths: trees are now keyed by their absolute root dir, so relative and absolute lookups both work. - Fix
Grovestamps.load()with nested top paths: yaml now loads into the deepest matching tree instead of the first. - Fix
Grovestamps.loadf(), which tried to parse the file’s parent directory instead of the file. - Fix crash on
Grovestampsconstruction and dump whenprogram_configcontains nested dicts, lists, or tuples. - Load and WAL errors are now reported through the
treestampslogger instead ofverbose-gated prints. Theverboseconfig field remains but no longer gates output. - Trees rooted at a file no longer consume (and delete on dump) stamp files found in subdirectories of the file’s parent.
- Fix WAL data loss:
Performance¶
get()stops walking ancestors at the tree root instead of the filesystem root.compact()scans the timestamp map with cheap string prefix compares.- Grove-created trees no longer re-normalize the program config per tree.
- Child stamp scanning is iterative, so very deep trees can’t hit Python’s recursion limit.
v4.0.2¶
- Fix
dumpfcrash when a parent-of-root yaml contains an entry pointing at the parent directory itself. Such entries are now clamped toroot_diron load (matching the v3 semantic: a timestamp on an ancestor of the tree applies to the tree as a whole), instead of being stored above-root and crashing_serialize_timestamps.
v4.0.1¶
- Grove.dumpf returns a tuple of all paths which dumped treestamps.
v4.0.0¶
- API
- Remove most printing and progress from treestamps. This is now the responsibility of treestamps users. Verbosity quiets the few remaining load prints on errors.
- loadf(), loads(), and dumpf() return booleans to help with any logging users might want to do.
- Remove deprecated load() & dump() methods entirely.
- Performance
- Big perf wins on the hot paths used by picopt and nudebomb. On a 10k-file synthetic tree (
bin/bench-treestamps):- Cold load ~3.0× faster (1.40s → 459ms)
set()~4.1× faster (8.5k → 35k ops/s)- WAL replay ~2.7× faster (1.71s → 627ms)
get()unchanged (parent-of-root timestamps are loaded into the cache soget()must still walk to the filesystem root).
- Big perf wins on the hot paths used by picopt and nudebomb. On a 10k-file synthetic tree (
- Internals:
- Load path uses ruamel safe-mode YAML instead of round-trip.
- WAL line append uses a hand-formatter for the common case, falling back to safe-mode YAML for keys with control characters.
- Child-tree walk uses
os.scandir(cached d_type, no extrastatper entry) instead ofPath.iterdir. _load_timestamp_entryuses an exact-key dict lookup instead of the ancestor-walking publicget()(also fixes a latent merge bug where parent-dir stamps could shadow newer file-level entries on load)._get_absolute_pathfast-paths relative inputs (the load case) to skip anos.getcwd()per entry.set()skips the WAL write and_changedflip when the supplied mtime is not newer than the cached one.dumpf()writes via temp file +os.replacefor atomic snapshots.- Ignore globs are precompiled. Single-segment globs (the common case:
*.tmp,__pycache__) compile to a regex matched againstpath.namedirectly, ~12× faster than the old per-callPath.match()glob re-compilation.
- Added
bin/bench-treestampsbenchmark script andtests/unit/test_wal_quote.pyfor the new WAL key quoter.
v3.0.3¶
- Fix wal & timestamps file creation to have config at the top
v3.0.2¶
- Flush wal entries more consistently
- Make wal more resistant to errors with filenames.
v3.0.1¶
- Setting timestamps on dirs doesn’t count for determining change as to when to actually dumpf() if there are changes.
v3.0.0¶
- Grovestamps no longer inherits from dict.
- Grovestamps.get_timestamp(top_path, path)
- Remove deprecated Grovestamps.dump() method.
- Remove deprecated Grovestamps.dumpf(noop_top_paths) signature.
v2.5.4¶
- Fix special characters in wal entrries
- Fix compact_all() calling nonextant method.
v2.5.3¶
- treestamps.compact_top() and grove.compact_all()
v2.5.2¶
- Allow treestamps config to be pickable
v2.5.1¶
- Add Grove.compact(top_path, path)
v2.5.0¶
- Simpler change detection based on treestamps.set()
- Params to dumpf() deprecated
- Add Grove.set(top_path, path, …)
v2.4.3¶
- Fix noop not writing timestamp if none exists.
v2.4.2¶
- Fix tree.dumpf() was counting the root wallfile as a consumed child timestamp.
v2.4.1¶
- dumpf() noop_top_paths closes wal files properly
- dumpf() noop_top_paths writes anyway if children treestamp files were consumed.
- Allow set & frozenset to dumpf() noop_top_paths for typechecking
v2.4.0¶
- Add skip_top_paths to grove.dumpf() to skip writing timestamps if nothing changed.
v2.3.1¶
- Add type hints and py.typed sentinel
- Better docs
v2.3.0¶
- Represent frozensets as yaml sets instead of mappings. Represent any Mapping type as mappings.
v2.2.7¶
- More flexible ruamel.yaml dependency.
v2.2.6¶
- Fix wal loading error message.
v2.2.5¶
- Update colors
v2.2.4¶
- Update termcolor
v2.2.3¶
- Fix error with printing saving timestamps
- Change color of compacting timestamps
v2.2.2¶
- More consistent printing and colors. Less verbosity by config.
v2.2.1¶
- Config elements that were MappingProxyTypes are now dicts. MPTs don’t pickle, which seems unfriendly.
v2.2.0¶
- Added:
- Grovestamps.loads(), .loadf(), .load_map(), .dump_dict(), .dumps(), .dumpf() methods
- Treestamps.loads(), .loadf(), .load_map(), .loadf_tree(), .dump_dict(), .dumps(), .dumpf() methods.
- Grovestamps.filename and Grovestamps.wal_filename properties
- Deprecate Grovestamps.dump(), use .dumpf()
- Deprecate Treestamps.load(), use .loadf_tree()
- Deprecate Treestamps.dump(), use .dumpf()
v2.1.1¶
- Fix dumps() method to take no arguments.
- Expose get_filename() method.
v2.1.0¶
- Add dumpf() and dumps() methods. Old dump() method is an alias for dumpf(). dumpf() calls cleanup_old_timestamps() automatically. dumps() must call it manually.
v2.0.0¶
- CHANGES WILL CAUSE ALL TIMESTAMPS TO MISS:
- Config elements are now converted to MappingProxyTypes, Tuples and frozensets
- Represent config id sets as sets in yaml
- Fix absolute path resolution.
- Change build system to uv
- Termcolor 3.0
v1.0.2¶
- Indent lists with an offset the way Prettier does.
v1.0.1¶
- Quote yaml keys in wal to handle illegal characters.
- Fixed incorrect, but still inadequate README docs.
v1.0.0¶
- Require Python 3.10
v0.4.4¶
- Fix
- Dependency updates and linting.
v0.4.3¶
- Fix
- Ensure use of absolute paths internally, relative paths externally.
- Features
- get() and set() now accept strings as well as paths.
v0.4.2¶
- Fix
- Make treestamp paths all relative again like 0.3.x for portability
- Keep reading WAL if individual entries are corrupt.
v0.4.1¶
- Fix
- Most paths generated improperly.
- check_config = False would crash.
v0.4.0¶
- Features
- Big API Changes see README
- Dev
- Refactor into different files.
v0.3.4¶
- Dev
- Update dependencies.
v0.3.3¶
- Features
- Update dependencies & uv.lockfile
v0.3.2¶
- Features
- Update dependencies & uv.lockfile
v0.3.1¶
- Fix
- Factory passed strings instead of paths crash.
v0.3.0¶
-
Fix
- Factory consuming child timestamps when given files not directories.
- Loading and dumping timestamps not related to the treestamp dir.
-
Features
- Ignore symlinks option.
v0.2.1¶
- Fix
- Support ignore in factory
v0.2.0¶
- Features
- Support ignore globs
v0.1.3¶
- Fixes
- Protect final dump yaml from child cleanup task.
v0.1.2¶
-
Features
- Colored output.
-
Fixes
- Trap more errors when reading timestamps
v0.1.1¶
- Fixes
- Fix strings submitted to factory instead of paths
v0.1.0¶
- Features
- Picopt’s new timestamper abstracted to a library