11import traceback
2+ from collections import namedtuple
23from dataclasses import (
34 dataclass ,
45 field ,
1516)
1617
1718from .exceptions import SnapshotDoesNotExist
19+ from .extensions .amber .serializer import Repr
1820
1921if TYPE_CHECKING :
2022 from .extensions .base import AbstractSyrupyExtension
@@ -54,8 +56,6 @@ class SnapshotAssertion:
5456 test_location : "PyTestLocation"
5557 update_snapshots : bool
5658
57- name : str = "snapshot"
58-
5959 _exclude : Optional ["PropertyFilter" ] = field (
6060 init = False ,
6161 default = None ,
@@ -76,6 +76,9 @@ class SnapshotAssertion:
7676 init = False ,
7777 default_factory = dict ,
7878 )
79+ _execution_name_index : Dict ["SnapshotIndex" , int ] = field (
80+ init = False , default_factory = dict
81+ )
7982 _matcher : Optional ["PropertyMatcher" ] = field (
8083 init = False ,
8184 default = None ,
@@ -104,7 +107,7 @@ def num_executions(self) -> int:
104107 return int (self ._executions )
105108
106109 @property
107- def executions (self ) -> Dict [int , AssertionResult ]:
110+ def executions (self ) -> Dict [int , " AssertionResult" ]:
108111 return self ._execution_results
109112
110113 @property
@@ -113,6 +116,44 @@ def index(self) -> "SnapshotIndex":
113116 return self ._custom_index
114117 return self .num_executions
115118
119+ @property
120+ def name (self ) -> str :
121+ return self ._custom_index or "snapshot"
122+
123+ @property
124+ def __repr (self ) -> "SerializableData" :
125+ SnapshotAssertionRepr = namedtuple ( # type: ignore
126+ "SnapshotAssertion" , ["name" , "num_executions" ]
127+ )
128+ assertion_result = self .executions .get (
129+ (self ._custom_index and self ._execution_name_index .get (self ._custom_index ))
130+ or self .num_executions - 1
131+ )
132+ return (
133+ Repr (str (assertion_result .final_data ))
134+ if assertion_result
135+ else SnapshotAssertionRepr (
136+ name = self .name ,
137+ num_executions = self .num_executions ,
138+ )
139+ )
140+
141+ @property
142+ def __matcher (self ) -> "PropertyMatcher" :
143+ """
144+ Get matcher that replaces `SnapshotAssertion` with one that can be serialized
145+ """
146+
147+ def _matcher (** kwargs : Any ) -> Optional ["SerializableData" ]:
148+ maybe_assertion = kwargs .get ("data" )
149+ if isinstance (maybe_assertion , SnapshotAssertion ):
150+ return maybe_assertion .__repr
151+ if self ._matcher :
152+ return self ._matcher (** kwargs )
153+ return maybe_assertion
154+
155+ return _matcher
156+
116157 def use_extension (
117158 self , extension_class : Optional [Type ["AbstractSyrupyExtension" ]] = None
118159 ) -> "SnapshotAssertion" :
@@ -132,7 +173,7 @@ def assert_match(self, data: "SerializableData") -> None:
132173
133174 def _serialize (self , data : "SerializableData" ) -> "SerializedData" :
134175 return self .extension .serialize (
135- data , exclude = self ._exclude , matcher = self ._matcher
176+ data , exclude = self ._exclude , matcher = self .__matcher
136177 )
137178
138179 def get_assert_diff (self ) -> List [str ]:
@@ -190,8 +231,8 @@ def __call__(
190231 self .__with_prop ("_snapshot_diff" , diff )
191232 return self
192233
193- def __dir__ (self ) -> List [ str ] :
194- return [ "name" , "num_executions" ]
234+ def __repr__ (self ) -> str :
235+ return str ( self . _serialize ( self . __repr ))
195236
196237 def __eq__ (self , other : "SerializableData" ) -> bool :
197238 return self ._assert (other )
@@ -233,6 +274,7 @@ def _assert(self, data: "SerializableData") -> bool:
233274 finally :
234275 snapshot_created = snapshot_data is None and assertion_success
235276 snapshot_updated = matches is False and assertion_success
277+ self ._execution_name_index [self .index ] = self ._executions
236278 self ._execution_results [self ._executions ] = AssertionResult (
237279 snapshot_location = snapshot_location ,
238280 snapshot_name = snapshot_name ,
0 commit comments