localstack-snapshot 0.3.1__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/PKG-INFO +1 -1
  2. localstack_snapshot-0.3.3/localstack_snapshot/__init__.py +1 -0
  3. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot/snapshots/prototype.py +29 -9
  4. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot.egg-info/PKG-INFO +1 -1
  5. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/pyproject.toml +1 -1
  6. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/tests/test_snapshots.py +77 -0
  7. localstack_snapshot-0.3.1/localstack_snapshot/__init__.py +0 -1
  8. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/LICENSE +0 -0
  9. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/README.md +0 -0
  10. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot/pytest/__init__.py +0 -0
  11. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot/pytest/snapshot.py +0 -0
  12. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot/snapshots/__init__.py +0 -0
  13. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot/snapshots/report.py +0 -0
  14. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot/snapshots/transformer.py +0 -0
  15. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot/snapshots/transformer_utility.py +0 -0
  16. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot/util/__init__.py +0 -0
  17. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot/util/encoding.py +0 -0
  18. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot.egg-info/SOURCES.txt +0 -0
  19. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot.egg-info/dependency_links.txt +0 -0
  20. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot.egg-info/requires.txt +0 -0
  21. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/localstack_snapshot.egg-info/top_level.txt +0 -0
  22. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/setup.cfg +0 -0
  23. {localstack_snapshot-0.3.1 → localstack_snapshot-0.3.3}/tests/test_transformer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: localstack-snapshot
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Extracted snapshot testing lib for LocalStack
5
5
  Author-email: LocalStack Contributors <info@localstack.cloud>
6
6
  License:
@@ -0,0 +1 @@
1
+ __version__ = "0.3.3"
@@ -2,7 +2,9 @@ import io
2
2
  import json
3
3
  import logging
4
4
  import os
5
+ from collections.abc import Iterator
5
6
  from datetime import datetime, timezone
7
+ from enum import Enum
6
8
  from json import JSONDecodeError
7
9
  from pathlib import Path
8
10
  from re import Pattern
@@ -169,16 +171,34 @@ class SnapshotSession:
169
171
  def match_object(self, key: str, obj: object) -> None:
170
172
  def _convert_object_to_dict(obj_):
171
173
  if isinstance(obj_, dict):
172
- for key in list(obj_.keys()):
173
- if key.startswith("_"):
174
- del obj_[key]
175
- else:
176
- obj_[key] = _convert_object_to_dict(obj_[key])
177
- elif isinstance(obj_, list):
178
- for idx, val in enumerate(obj_):
179
- obj_[idx] = _convert_object_to_dict(val)
174
+ # Serialize the values of the dictionary, while skipping any private keys (starting with '_')
175
+ return {
176
+ key_: _convert_object_to_dict(obj_[key_])
177
+ for key_ in obj_
178
+ if not key_.startswith("_")
179
+ }
180
+ elif isinstance(obj_, (list, Iterator)):
181
+ return [_convert_object_to_dict(val) for val in obj_]
182
+ elif isinstance(obj_, Enum):
183
+ return obj_.value
180
184
  elif hasattr(obj_, "__dict__"):
181
- return _convert_object_to_dict(obj_.__dict__)
185
+ # This is an object - let's try to convert it to a dictionary
186
+ # A naive approach would be to use the '__dict__' object directly, but that only lists the attributes.
187
+ # In order to also serialize the properties, we use the __dir__() method
188
+ # Filtering by everything that is not a method gives us both attributes and properties
189
+ # We also (still) skip private attributes/properties, so everything that starts with an underscore.
190
+ return {
191
+ k: _convert_object_to_dict(getattr(obj_, k))
192
+ for k in obj_.__dir__()
193
+ if (
194
+ # Skip private attributes
195
+ not k.startswith("_")
196
+ # Skip everything that's not a method
197
+ and type(getattr(obj_, k, "")).__name__ != "method"
198
+ # Skip everything that refers to itself (identity functions), as that leads to recursion
199
+ and getattr(obj_, k) != obj_
200
+ )
201
+ }
182
202
  return obj_
183
203
 
184
204
  return self.match(key, _convert_object_to_dict(obj))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: localstack-snapshot
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Extracted snapshot testing lib for LocalStack
5
5
  Author-email: LocalStack Contributors <info@localstack.cloud>
6
6
  License:
@@ -7,7 +7,7 @@ name = "localstack-snapshot"
7
7
  authors = [
8
8
  { name = "LocalStack Contributors", email = "info@localstack.cloud" }
9
9
  ]
10
- version = "0.3.1"
10
+ version = "0.3.3"
11
11
  description = "Extracted snapshot testing lib for LocalStack"
12
12
  dependencies = [
13
13
  "jsonpath-ng>1.6",
@@ -1,4 +1,5 @@
1
1
  import io
2
+ from enum import Enum
2
3
 
3
4
  import pytest
4
5
 
@@ -75,6 +76,82 @@ class TestSnapshotManager:
75
76
  sm.match_object("key_a", CustomObject(name="myname"))
76
77
  sm._assert_all()
77
78
 
79
+ def test_match_object_lists_and_iterators(self):
80
+ class CustomObject:
81
+ def __init__(self, name):
82
+ self.name = name
83
+ self.my_list = [9, 8, 7, 6, 5]
84
+ self.my_iterator = (x for x in range(5))
85
+
86
+ sm = SnapshotSession(scope_key="A", verify=True, base_file_path="", update=False)
87
+ sm.recorded_state = {
88
+ "key_a": {"name": "myname", "my_iterator": [0, 1, 2, 3, 4], "my_list": [9, 8, 7, 6, 5]}
89
+ }
90
+ sm.match_object("key_a", CustomObject(name="myname"))
91
+ sm._assert_all()
92
+
93
+ def test_match_object_include_properties(self):
94
+ class CustomObject:
95
+ def __init__(self, name):
96
+ self.name = name
97
+ self._internal = "n/a"
98
+
99
+ def some_method(self):
100
+ # method should not be serialized
101
+ return False
102
+
103
+ @property
104
+ def some_prop(self):
105
+ # properties should be serialized
106
+ return True
107
+
108
+ @property
109
+ def some_iterator(self):
110
+ for i in range(3):
111
+ yield i
112
+
113
+ @property
114
+ def _private_prop(self):
115
+ # private properties should be ignored
116
+ return False
117
+
118
+ sm = SnapshotSession(scope_key="A", verify=True, base_file_path="", update=False)
119
+ sm.recorded_state = {
120
+ "key_a": {"name": "myname", "some_prop": True, "some_iterator": [0, 1, 2]}
121
+ }
122
+ sm.match_object("key_a", CustomObject(name="myname"))
123
+ sm._assert_all()
124
+
125
+ def test_match_object_enums(self):
126
+ class TestEnum(Enum):
127
+ value1 = "Value 1"
128
+ value2 = "Value 2"
129
+
130
+ class CustomObject:
131
+ def __init__(self, name):
132
+ self.name = name
133
+ self.my_enum = TestEnum.value2
134
+
135
+ sm = SnapshotSession(scope_key="A", verify=True, base_file_path="", update=False)
136
+ sm.recorded_state = {"key_a": {"name": "myname", "my_enum": "Value 2"}}
137
+ sm.match_object("key_a", CustomObject(name="myname"))
138
+ sm._assert_all()
139
+
140
+ def test_match_object_with_identity_function(self):
141
+ class CustomObject:
142
+ def __init__(self, name):
143
+ self.name = name
144
+
145
+ @property
146
+ def me_myself_and_i(self):
147
+ # This would lead to a RecursionError, so we cannot snapshot this method
148
+ return self
149
+
150
+ sm = SnapshotSession(scope_key="A", verify=True, base_file_path="", update=False)
151
+ sm.recorded_state = {"key_a": {"name": "myname"}}
152
+ sm.match_object("key_a", CustomObject(name="myname"))
153
+ sm._assert_all()
154
+
78
155
  def test_match_object_change(self):
79
156
  class CustomObject:
80
157
  def __init__(self, name):
@@ -1 +0,0 @@
1
- __version__ = "0.3.1"