or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cli-integration.mdcore-assertions.mdextensions.mdfilters.mdindex.mdmatchers.md
tile.json

tessl/pypi-syrupy

Pytest snapshot testing utility that enables developers to write tests asserting immutability of computed results.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/syrupy@4.9.x

To install, run

npx @tessl/cli install tessl/pypi-syrupy@4.9.0

index.mddocs/

Syrupy

A zero-dependency pytest snapshot testing library that enables developers to write tests asserting immutability of computed results. Syrupy provides an extensible and idiomatic approach to snapshot testing with the syntax assert x == snapshot, offering comprehensive filtering, matching, and custom serialization capabilities.

Package Information

  • Package Name: syrupy
  • Language: Python
  • Installation: pip install syrupy
  • Requirements: Python >=3.8.1, pytest >=7.0.0,<9.0.0

Core Imports

import syrupy

Standard usage in tests:

def test_example(snapshot):
    assert result == snapshot

Extension imports:

from syrupy.extensions.amber import AmberSnapshotExtension
from syrupy.extensions.json import JSONSnapshotExtension
from syrupy.extensions.image import PNGImageSnapshotExtension, SVGImageSnapshotExtension
from syrupy.extensions.single_file import SingleFileSnapshotExtension, SingleFileAmberSnapshotExtension, WriteMode

Matcher and filter imports:

from syrupy.matchers import path_type, path_value, compose_matchers
from syrupy.filters import props, paths, paths_include

Exception imports:

from syrupy.exceptions import SnapshotDoesNotExist, FailedToLoadModuleMember, TaintedSnapshotError
from syrupy.matchers import PathTypeError, StrictPathTypeError

Basic Usage

def test_basic_snapshot(snapshot):
    """Basic snapshot testing - creates .ambr file in __snapshots__ directory"""
    actual = {"name": "Alice", "age": 30, "scores": [85, 92, 78]}
    assert actual == snapshot

def test_with_index(snapshot):
    """Multiple snapshots in one test"""
    assert "first result" == snapshot
    assert "second result" == snapshot

def test_custom_extension(snapshot):
    """Using JSON extension for dictionary data"""
    from syrupy.extensions.json import JSONSnapshotExtension
    
    data = {"users": [{"id": 1, "name": "Alice"}]}
    assert data == snapshot.use_extension(JSONSnapshotExtension)

def test_with_matchers(snapshot):
    """Using matchers to handle dynamic data"""
    from syrupy.matchers import path_type
    
    result = {
        "timestamp": "2023-12-01T10:30:00Z",  # Dynamic value
        "user_id": 12345,  # Dynamic value  
        "message": "Hello world"  # Static value
    }
    
    # Replace dynamic values with placeholders
    assert result == snapshot(matcher=path_type({
        "timestamp": (str, "<timestamp>"),
        "user_id": (int, "<user_id>")
    }))

def test_with_filters(snapshot):
    """Using filters to include/exclude properties"""
    from syrupy.filters import props
    
    data = {
        "public_field": "visible",
        "private_field": "hidden",
        "internal_field": "secret"
    }
    
    # Only include public fields
    assert data == snapshot(include=props("public_field"))

Architecture

Syrupy uses an extensible architecture built around several key components:

  • SnapshotAssertion: Main assertion class providing fluent interface for configuration
  • Extensions: Pluggable serialization and storage backends (Amber, JSON, PNG, SVG, etc.)
  • Matchers: Value transformation system for handling dynamic data
  • Filters: Property inclusion/exclusion system for controlling serialization scope
  • Session Management: pytest integration handling snapshot lifecycle and reporting

The pytest plugin automatically registers hooks and provides the snapshot fixture, making snapshot testing seamlessly integrate with existing test suites.

Capabilities

Core Snapshot Assertions

Primary snapshot assertion functionality with fluent interface for configuration, including basic assertions, indexed snapshots, and method chaining for custom behavior.

class SnapshotAssertion:
    def __call__(self, *, matcher=None, include=None, exclude=None, extension_class=None): ...
    def __eq__(self, other): ...
    def use_extension(self, extension_class): ...
    def with_defaults(self, **kwargs): ...

Core Assertions

Extensions System

Pluggable serialization and storage system supporting multiple output formats including Amber (default multi-snapshot), JSON, PNG, SVG, and raw file formats with extensible base classes.

class AbstractSyrupyExtension: ...
class AmberSnapshotExtension(AbstractSyrupyExtension): ...
class JSONSnapshotExtension(AbstractSyrupyExtension): ...
class PNGImageSnapshotExtension(AbstractSyrupyExtension): ...
class SVGImageSnapshotExtension(AbstractSyrupyExtension): ...

Extensions

Matchers

Value transformation system for handling dynamic data in snapshots, providing path-based matching with type replacement and regex-based value substitution.

def path_type(mapping: Dict[str, Tuple[type, Any]], *, strict: bool = True): ...
def path_value(mapping: Dict[str, Any]): ...
def compose_matchers(*matchers): ...

Matchers

Filters

Property inclusion and exclusion system for controlling serialization scope, supporting path-based and property-based filtering with nested path handling.

def props(*included: str): ...
def paths(*included: str): ...
def paths_include(*nested_paths: str): ...

Filters

CLI Integration

Command-line options and pytest integration providing snapshot update modes, reporting configuration, and extension selection.

def pytest_addoption(parser): ...
@pytest.fixture
def snapshot(request): ...

CLI Integration

Types

from typing import Union, Any, Callable, Tuple, Hashable, Type, List, Optional
import re

# Core types
SnapshotIndex = Union[int, str]
SerializableData = Any
SerializedData = Union[str, bytes] 

# Property system types
PropertyName = Hashable
PropertyValueType = Type[SerializableData]
PropertyPathEntry = Tuple[PropertyName, PropertyValueType]
PropertyPath = Tuple[PropertyPathEntry, ...]
PropertyMatcher = Callable[[SerializableData, PropertyPath], Optional[SerializableData]]
PropertyFilter = Callable[[PropertyName, PropertyPath], bool]

# Matcher helper types
try:
    MatchResult = Optional[re.Match[str]]
except TypeError:
    MatchResult = Optional[re.Match]
Replacer = Callable[[SerializableData, MatchResult], SerializableData]

# Assertion result
@dataclass
class AssertionResult:
    snapshot_location: str
    snapshot_name: str
    asserted_data: Optional[SerializedData]
    recalled_data: Optional[SerializedData]
    created: bool
    updated: bool
    success: bool
    exception: Optional[Exception]
    test_location: "PyTestLocation"
    
    @property
    def final_data(self) -> Optional[SerializedData]: ...

# Diff mode
class DiffMode(Enum):
    DETAILED = "detailed"
    DISABLED = "disabled"

Exceptions

class SnapshotDoesNotExist(Exception):
    """Raised when a snapshot file or entry doesn't exist"""

class FailedToLoadModuleMember(Exception):
    """Raised when unable to load a module member"""

class TaintedSnapshotError(Exception):
    """Raised when snapshot is corrupted and needs regeneration"""

class PathTypeError(TypeError):
    """Raised when path type matching encounters an error"""

class StrictPathTypeError(PathTypeError):
    """Raised when strict path type matching fails due to type mismatch"""