Upgrading¶
Upgrading to 2.0¶
pytest-ditto 2.0 changes the unmarked default from pickle to strict JSON and
removes pickle from the core distribution. Existing .pkl snapshots are
ignored by the JSON path: core does not inspect, load, compare, convert, or
migrate them.
When a .json snapshot is absent, a normal or update run follows ordinary
missing-snapshot behavior and records current test output as new JSON, even if
a same-key .pkl file exists. A read-only verification run reports the JSON key
as missing. Re-recording does not prove that the current output is equivalent
to the old baseline.
Use this upgrade workflow:
- Upgrade and run the complete test suite to create missing JSON snapshots.
- For strict-JSON failures, change the snapshotted representation or select a suitable installed recorder.
- Review every new JSON snapshot. It was recorded from current output, not converted or compared with pickle.
- Run the complete suite again.
- Run
ditto lockonly after accepting the new baselines. - Remove old
.pklsnapshots manually or through the ordinary prune workflow.
If pickle is deliberately required, install pytest-ditto-pickle and select
its recorder explicitly. Loading pickle data can execute arbitrary code, so
only load trusted snapshots. Core provides no pickle warning, guard, migration
command, or convenience extra.
pytest-ditto-pickle names its snapshot files after the recorder, so they end
in .pickle, not .pkl. A 1.x .pkl file must already be renamed to its 2.0
key to be found; give the renamed file the .pickle ending. If you used
pytest-ditto-pickle 2.0.0b1, which still wrote .pkl, rename those snapshots
to end in .pickle and run ditto lock.
Version 2.0 registers the pytest plugin under the name ditto instead of
recording, which collided with the pytest-recording plugin. To disable
pytest-ditto for a run, use -p no:ditto in place of -p no:recording.
Version 2.0 also removes DittoTestCase. Unittest-style classes collected by
pytest should use pytest fixtures and marks. Direct Snapshot construction is
the lower-level alternative when fixture injection is unsuitable.
A directly constructed Snapshot takes a single mode in place of the
update and readonly flags: Snapshot(..., mode=SnapshotMode.UPDATE) replaces
update=True, and mode=SnapshotMode.VERIFY replaces readonly=True. The
default, SnapshotMode.RECORD, matches the old defaults. Import SnapshotMode
from ditto. A Snapshot given a recorder also needs recorder_name=, the
name the recorder is registered under, which names its snapshot files:
Snapshot(..., recorder=recorders.get("yaml"), recorder_name="yaml"). Passing
one without the other raises TypeError. Omit both for strict JSON.
Recorders serialise to bytes: a Recorder is Recorder(dumps=..., loads=...),
where dumps turns a value into the snapshot file's bytes and loads turns
them back. The path-based Recorder(save=..., load=...) is gone. A plugin still
built on it fails to load with a message saying so. Rebuild it on the
library's in-memory functions, or wrap its file functions with
ditto.recorders.recorder_from_files. See
Custom Recorders.
snapshot() now returns the value as the recorder reads it back on every run.
Before, the run that recorded or updated a snapshot, or verified a missing one,
returned the value passed in. A value the recorder doesn't store exactly used
to pass on that run and fail on the next one; it now fails straight away. For
example, the YAML recorder reads a tuple back as a list, so
assert (1, 2) == snapshot((1, 2), key="pair") under @ditto.yaml now fails
when first recorded. Snapshot a list instead, or use a recorder that keeps the
distinction. A recorder whose loads can't read the bytes its dumps produced
now raises before anything is written.
YAML and pytest-ditto-pandas CSV snapshots are now written with "\n" line
endings on every platform, as JSON already was. On Windows, snapshots those
recorders wrote before used "\r\n". They still load; the next
--ditto-update rewrites them with "\n", a one-time line-ending diff.
Git on Windows often converts line endings on checkout (core.autocrlf), which
gives a working copy with "\r\n" while ditto writes "\n". Snapshots still
load, but to keep them byte-for-byte what ditto wrote, add this to your
repository's .gitattributes:
If snapshots live in a directory other than .ditto, for example one set with
ditto_target, add a line for that directory too.
Snapshot Key Format Change¶
Recent versions changed how snapshot keys are derived. Snapshots recorded by older versions will not be found after upgrading:
file://snapshots are now stored as flatmodule.group@key.extfiles (one.ditto/directory, no per-module subdirectories)- Class-based test keys now include the class name
(
TestClass.test_methodrather thantest_method)
Migration Steps¶
Because a missing snapshot is recorded and passes rather than failing, an upgrade will silently re-record every snapshot from your code's current output on the next run.
To avoid masking a regression:
-
Re-record deliberately with
--ditto-update: -
Review the regenerated snapshots in your diff — do not trust the first green run after upgrading
-
Commit the updated snapshots once you're satisfied
Migration from ditto_backend¶
If you previously used a ditto_backend fixture, migrate to the
target= + backend registration model:
-
Register a URI scheme under
ditto_backends: -
Move runtime auth and connection kwargs into
ditto_storage_options: -
Select the backend with
target=orditto_target: