pytest-jsonschema-snapshot 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- pytest_jsonschema_snapshot/__init__.py +1 -1
- pytest_jsonschema_snapshot/core.py +41 -9
- pytest_jsonschema_snapshot/plugin.py +65 -5
- pytest_jsonschema_snapshot/tools/genson_addon/to_schema_converter.py +81 -100
- {pytest_jsonschema_snapshot-0.2.0.dist-info → pytest_jsonschema_snapshot-0.2.1.dist-info}/METADATA +3 -3
- {pytest_jsonschema_snapshot-0.2.0.dist-info → pytest_jsonschema_snapshot-0.2.1.dist-info}/RECORD +9 -9
- {pytest_jsonschema_snapshot-0.2.0.dist-info → pytest_jsonschema_snapshot-0.2.1.dist-info}/WHEEL +0 -0
- {pytest_jsonschema_snapshot-0.2.0.dist-info → pytest_jsonschema_snapshot-0.2.1.dist-info}/entry_points.txt +0 -0
- {pytest_jsonschema_snapshot-0.2.0.dist-info → pytest_jsonschema_snapshot-0.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -25,7 +25,10 @@ class SchemaShot:
|
|
|
25
25
|
root_dir: Path,
|
|
26
26
|
differ: "JsonSchemaDiff",
|
|
27
27
|
callable_regex: str = "{class_method=.}",
|
|
28
|
+
format_mode: str = "on",
|
|
28
29
|
update_mode: bool = False,
|
|
30
|
+
reset_mode: bool = False,
|
|
31
|
+
update_actions: dict[str, bool] = {},
|
|
29
32
|
save_original: bool = False,
|
|
30
33
|
debug_mode: bool = False,
|
|
31
34
|
snapshot_dir_name: str = "__snapshots__",
|
|
@@ -41,7 +44,11 @@ class SchemaShot:
|
|
|
41
44
|
self.root_dir: Path = root_dir
|
|
42
45
|
self.differ: "JsonSchemaDiff" = differ
|
|
43
46
|
self.callable_regex: str = callable_regex
|
|
47
|
+
self.format_mode: str = format_mode
|
|
48
|
+
# self.examples_limit: int = examples_limit
|
|
44
49
|
self.update_mode: bool = update_mode
|
|
50
|
+
self.reset_mode: bool = reset_mode
|
|
51
|
+
self.update_actions: dict[str, bool] = update_actions
|
|
45
52
|
self.save_original: bool = save_original
|
|
46
53
|
self.debug_mode: bool = debug_mode
|
|
47
54
|
self.snapshot_dir: Path = root_dir / snapshot_dir_name
|
|
@@ -104,7 +111,9 @@ class SchemaShot:
|
|
|
104
111
|
available_to_create = not json_path.exists() or status is None
|
|
105
112
|
available_to_update = status is True
|
|
106
113
|
|
|
107
|
-
if available_to_create or
|
|
114
|
+
if (available_to_create and self.update_actions.get("add")) or (
|
|
115
|
+
available_to_update and self.update_actions.get("update")
|
|
116
|
+
):
|
|
108
117
|
with open(json_path, "w", encoding="utf-8") as f:
|
|
109
118
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
110
119
|
|
|
@@ -114,7 +123,7 @@ class SchemaShot:
|
|
|
114
123
|
GLOBAL_STATS.add_updated(json_name)
|
|
115
124
|
else:
|
|
116
125
|
raise ValueError(f"Unexpected status: {status}")
|
|
117
|
-
elif json_path.exists():
|
|
126
|
+
elif json_path.exists() and self.update_actions.get("delete"):
|
|
118
127
|
# удаляем
|
|
119
128
|
json_path.unlink()
|
|
120
129
|
GLOBAL_STATS.add_deleted(json_name)
|
|
@@ -135,13 +144,15 @@ class SchemaShot:
|
|
|
135
144
|
|
|
136
145
|
real_name = self._process_name(name)
|
|
137
146
|
|
|
138
|
-
builder = JsonToSchemaConverter(
|
|
147
|
+
builder = JsonToSchemaConverter(
|
|
148
|
+
format_mode=self.format_mode # type: ignore[arg-type]
|
|
149
|
+
) # , examples=self.examples_limit)
|
|
139
150
|
builder.add_object(data)
|
|
140
151
|
current_schema = builder.to_schema()
|
|
141
152
|
|
|
142
153
|
real_name, status = self._base_match(data, current_schema, real_name)
|
|
143
154
|
|
|
144
|
-
if self.update_mode:
|
|
155
|
+
if self.update_mode or self.reset_mode:
|
|
145
156
|
self._save_process_original(real_name=real_name, status=status, data=data)
|
|
146
157
|
|
|
147
158
|
return status
|
|
@@ -199,11 +210,15 @@ class SchemaShot:
|
|
|
199
210
|
|
|
200
211
|
# --- когда схемы ещё нет ---
|
|
201
212
|
if not schema_exists_before:
|
|
202
|
-
if not self.update_mode:
|
|
213
|
+
if not self.update_mode and not self.reset_mode:
|
|
203
214
|
raise pytest.fail.Exception(
|
|
204
215
|
f"Schema `{name}` not found."
|
|
205
216
|
"Run the test with the --schema-update option to create it."
|
|
206
217
|
)
|
|
218
|
+
elif not self.update_actions.get("add"):
|
|
219
|
+
raise pytest.fail.Exception(
|
|
220
|
+
f"Schema `{name}` not found and adding new schemas is disabled."
|
|
221
|
+
)
|
|
207
222
|
|
|
208
223
|
with open(schema_path, "w", encoding="utf-8") as f:
|
|
209
224
|
json.dump(current_schema, f, indent=2, ensure_ascii=False)
|
|
@@ -221,13 +236,30 @@ class SchemaShot:
|
|
|
221
236
|
if existing_schema != current_schema: # есть отличия
|
|
222
237
|
differences = self.differ.compare(dict(existing_schema), current_schema).render()
|
|
223
238
|
|
|
224
|
-
if self.update_mode:
|
|
239
|
+
if (self.update_mode or self.reset_mode) and self.update_actions.get("update"):
|
|
225
240
|
GLOBAL_STATS.add_updated(schema_path.name, differences)
|
|
226
241
|
|
|
227
242
|
# обновляем файл
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
243
|
+
if self.reset_mode and not self.update_mode:
|
|
244
|
+
with open(schema_path, "w", encoding="utf-8") as f:
|
|
245
|
+
json.dump(current_schema, f, indent=2, ensure_ascii=False)
|
|
246
|
+
self.logger.warning(f"Schema `{name}` updated (reset).\n\n{differences}")
|
|
247
|
+
elif self.update_mode and not self.reset_mode:
|
|
248
|
+
builder = JsonToSchemaConverter(
|
|
249
|
+
format_mode=self.format_mode # type: ignore[arg-type]
|
|
250
|
+
) # , examples=self.examples_limit)
|
|
251
|
+
builder.add_schema(existing_schema)
|
|
252
|
+
builder.add_schema(current_schema)
|
|
253
|
+
merged_schema = builder.to_schema()
|
|
254
|
+
|
|
255
|
+
with open(schema_path, "w", encoding="utf-8") as f:
|
|
256
|
+
json.dump(merged_schema, f, indent=2, ensure_ascii=False)
|
|
257
|
+
|
|
258
|
+
self.logger.warning(f"Schema `{name}` updated (update).\n\n{differences}")
|
|
259
|
+
else: # both update_mode and reset_mode are True
|
|
260
|
+
raise ValueError(
|
|
261
|
+
"Both update_mode and reset_mode cannot be True at the same time."
|
|
262
|
+
)
|
|
231
263
|
schema_updated = True
|
|
232
264
|
elif data is not None:
|
|
233
265
|
GLOBAL_STATS.add_uncommitted(schema_path.name, differences)
|
|
@@ -22,7 +22,16 @@ def pytest_addoption(parser: pytest.Parser) -> None:
|
|
|
22
22
|
parser.addoption(
|
|
23
23
|
"--schema-update",
|
|
24
24
|
action="store_true",
|
|
25
|
-
help=
|
|
25
|
+
help=(
|
|
26
|
+
"Augmenting mode for updating schemas. "
|
|
27
|
+
"If something is valid for the old schema, then it is valid "
|
|
28
|
+
"for the new one (and vice versa)."
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
parser.addoption(
|
|
32
|
+
"--schema-reset",
|
|
33
|
+
action="store_true",
|
|
34
|
+
help="New schema does not take into account the old one during update.",
|
|
26
35
|
)
|
|
27
36
|
parser.addoption(
|
|
28
37
|
"--save-original",
|
|
@@ -35,6 +44,22 @@ def pytest_addoption(parser: pytest.Parser) -> None:
|
|
|
35
44
|
help="Show internal exception stack (stops hiding them)",
|
|
36
45
|
)
|
|
37
46
|
|
|
47
|
+
parser.addoption(
|
|
48
|
+
"--without-delete",
|
|
49
|
+
action="store_true",
|
|
50
|
+
help="Disable deleting unused schemas",
|
|
51
|
+
)
|
|
52
|
+
parser.addoption(
|
|
53
|
+
"--without-update",
|
|
54
|
+
action="store_true",
|
|
55
|
+
help="Disable updating schemas",
|
|
56
|
+
)
|
|
57
|
+
parser.addoption(
|
|
58
|
+
"--without-add",
|
|
59
|
+
action="store_true",
|
|
60
|
+
help="Disable adding new schemas",
|
|
61
|
+
)
|
|
62
|
+
|
|
38
63
|
parser.addini(
|
|
39
64
|
"jsss_dir",
|
|
40
65
|
default="__snapshots__",
|
|
@@ -45,6 +70,11 @@ def pytest_addoption(parser: pytest.Parser) -> None:
|
|
|
45
70
|
default="{class_method=.}",
|
|
46
71
|
help="Regex for saving callable part of path",
|
|
47
72
|
)
|
|
73
|
+
parser.addini(
|
|
74
|
+
"jsss_format_mode",
|
|
75
|
+
default="on",
|
|
76
|
+
help="Format mode: 'on' (annotate and validate), 'safe' (annotate), 'off' (disable)",
|
|
77
|
+
)
|
|
48
78
|
|
|
49
79
|
|
|
50
80
|
@pytest.fixture(scope="function")
|
|
@@ -56,13 +86,26 @@ def schemashot(request: pytest.FixtureRequest) -> Generator[SchemaShot, None, No
|
|
|
56
86
|
# Получаем путь к тестовому файлу
|
|
57
87
|
test_path = Path(request.node.path if hasattr(request.node, "path") else request.node.fspath)
|
|
58
88
|
root_dir = test_path.parent
|
|
89
|
+
|
|
59
90
|
update_mode = bool(request.config.getoption("--schema-update"))
|
|
91
|
+
reset_mode = bool(request.config.getoption("--schema-reset"))
|
|
92
|
+
if update_mode and reset_mode:
|
|
93
|
+
raise ValueError("Options --schema-update and --schema-reset are mutually exclusive.")
|
|
94
|
+
|
|
60
95
|
save_original = bool(request.config.getoption("--save-original"))
|
|
61
96
|
debug_mode = bool(request.config.getoption("--jsss-debug"))
|
|
62
97
|
|
|
98
|
+
actions = {
|
|
99
|
+
"delete": not request.config.getoption("--without-delete"),
|
|
100
|
+
"update": not request.config.getoption("--without-update"),
|
|
101
|
+
"add": not request.config.getoption("--without-add"),
|
|
102
|
+
}
|
|
103
|
+
|
|
63
104
|
# Получаем настраиваемую директорию для схем
|
|
64
105
|
schema_dir_name = str(request.config.getini("jsss_dir"))
|
|
65
106
|
callable_regex = str(request.config.getini("jsss_callable_regex"))
|
|
107
|
+
format_mode = str(request.config.getini("jsss_format_mode")).lower()
|
|
108
|
+
# examples_limit = int(request.config.getini("jsss_examples_limit"))
|
|
66
109
|
|
|
67
110
|
differ = JsonSchemaDiff(
|
|
68
111
|
ConfigMaker.make(),
|
|
@@ -77,7 +120,11 @@ def schemashot(request: pytest.FixtureRequest) -> Generator[SchemaShot, None, No
|
|
|
77
120
|
root_dir,
|
|
78
121
|
differ,
|
|
79
122
|
callable_regex,
|
|
123
|
+
format_mode,
|
|
124
|
+
# examples_limit,
|
|
80
125
|
update_mode,
|
|
126
|
+
reset_mode,
|
|
127
|
+
actions,
|
|
81
128
|
save_original,
|
|
82
129
|
debug_mode,
|
|
83
130
|
schema_dir_name,
|
|
@@ -108,11 +155,21 @@ def pytest_terminal_summary(terminalreporter: pytest.TerminalReporter, exitstatu
|
|
|
108
155
|
"""
|
|
109
156
|
# Выполняем cleanup перед показом summary
|
|
110
157
|
if _schema_managers:
|
|
111
|
-
|
|
158
|
+
|
|
159
|
+
def get_opt(opt: str) -> bool:
|
|
160
|
+
return bool(terminalreporter.config.getoption(opt))
|
|
161
|
+
|
|
162
|
+
update_mode = get_opt("--schema-update")
|
|
163
|
+
|
|
164
|
+
actions = {
|
|
165
|
+
"delete": not get_opt("--without-delete"),
|
|
166
|
+
"update": not get_opt("--without-update"),
|
|
167
|
+
"add": not get_opt("--without-add"),
|
|
168
|
+
}
|
|
112
169
|
|
|
113
170
|
# Вызываем метод очистки неиспользованных схем для каждого экземпляра
|
|
114
171
|
for _root_dir, manager in _schema_managers.items():
|
|
115
|
-
cleanup_unused_schemas(manager, update_mode, GLOBAL_STATS)
|
|
172
|
+
cleanup_unused_schemas(manager, update_mode, actions, GLOBAL_STATS)
|
|
116
173
|
|
|
117
174
|
# Используем новую функцию для вывода статистики
|
|
118
175
|
update_mode = bool(terminalreporter.config.getoption("--schema-update"))
|
|
@@ -120,7 +177,10 @@ def pytest_terminal_summary(terminalreporter: pytest.TerminalReporter, exitstatu
|
|
|
120
177
|
|
|
121
178
|
|
|
122
179
|
def cleanup_unused_schemas(
|
|
123
|
-
manager: SchemaShot,
|
|
180
|
+
manager: SchemaShot,
|
|
181
|
+
update_mode: bool,
|
|
182
|
+
actions: dict[str, bool],
|
|
183
|
+
stats: Optional[SchemaStats] = None,
|
|
124
184
|
) -> None:
|
|
125
185
|
"""
|
|
126
186
|
Deletes unused schemas in update mode and collects statistics.
|
|
@@ -140,7 +200,7 @@ def cleanup_unused_schemas(
|
|
|
140
200
|
|
|
141
201
|
for schema_file in all_schemas:
|
|
142
202
|
if schema_file.name not in manager.used_schemas:
|
|
143
|
-
if update_mode:
|
|
203
|
+
if update_mode and actions.get("delete"):
|
|
144
204
|
try:
|
|
145
205
|
# Удаляем саму схему
|
|
146
206
|
schema_file.unlink()
|
|
@@ -1,119 +1,100 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
1
|
+
"""Json → Schema with optional format handling.
|
|
2
|
+
|
|
3
|
+
`format_mode` options
|
|
4
|
+
---------------------
|
|
5
|
+
* ``"on"`` – detect formats and let validators assert them (default).
|
|
6
|
+
* ``"off"`` – ignore formats entirely.
|
|
7
|
+
* ``"safe"`` – keep the annotations but embed a ``$vocabulary`` block that
|
|
8
|
+
**disables** the draft‑2020‑12 *format‑assertion* vocabulary.
|
|
9
|
+
This makes every ``format`` purely informational, regardless
|
|
10
|
+
of validator settings.
|
|
3
11
|
"""
|
|
4
12
|
|
|
5
|
-
from typing import Any, Dict,
|
|
13
|
+
from typing import Any, Dict, Literal
|
|
6
14
|
|
|
7
15
|
from genson import SchemaBuilder # type: ignore[import-untyped]
|
|
8
16
|
|
|
9
17
|
from .format_detector import FormatDetector
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
class FormatAwareString:
|
|
13
|
-
"""Strategy for strings with format detection"""
|
|
14
|
-
|
|
15
|
-
def __init__(self) -> None:
|
|
16
|
-
self.formats: set = set()
|
|
17
|
-
|
|
18
|
-
def match_schema(self, obj: Any) -> bool:
|
|
19
|
-
"""Checks if the object matches this strategy"""
|
|
20
|
-
return isinstance(obj, str)
|
|
21
|
-
|
|
22
|
-
def match_object(self, obj: Any) -> bool:
|
|
23
|
-
"""Checks if the object matches this strategy"""
|
|
24
|
-
return isinstance(obj, str)
|
|
25
|
-
|
|
26
|
-
def add_object(self, obj: Any) -> None:
|
|
27
|
-
"""Adds an object for analysis"""
|
|
28
|
-
if isinstance(obj, str):
|
|
29
|
-
detected_format = FormatDetector.detect_format(obj)
|
|
30
|
-
if detected_format:
|
|
31
|
-
self.formats.add(detected_format)
|
|
32
|
-
|
|
33
|
-
def to_schema(self) -> Dict[str, Any]:
|
|
34
|
-
"""Generates a schema for the string"""
|
|
35
|
-
schema = {"type": "string"}
|
|
36
|
-
|
|
37
|
-
# If all strings have the same format, add it to the schema
|
|
38
|
-
if len(self.formats) == 1:
|
|
39
|
-
schema["format"] = list(self.formats)[0]
|
|
40
|
-
|
|
41
|
-
return schema
|
|
19
|
+
_FormatMode = Literal["on", "off", "safe"]
|
|
42
20
|
|
|
43
21
|
|
|
44
22
|
class JsonToSchemaConverter(SchemaBuilder):
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
23
|
+
"""A thin wrapper around :class:`genson.SchemaBuilder`."""
|
|
24
|
+
|
|
25
|
+
# ------------------------------------------------------------------
|
|
26
|
+
# Construction
|
|
27
|
+
# ------------------------------------------------------------------
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
schema_uri: str = "https://json-schema.org/draft/2020-12/schema",
|
|
31
|
+
*,
|
|
32
|
+
format_mode: _FormatMode = "on",
|
|
33
|
+
):
|
|
34
|
+
super().__init__(schema_uri) if schema_uri else super().__init__()
|
|
35
|
+
if format_mode not in {"on", "off", "safe"}:
|
|
36
|
+
raise ValueError("format_mode must be 'on', 'off', or 'safe'.")
|
|
37
|
+
self._format_mode: _FormatMode = format_mode
|
|
38
|
+
self._format_cache: Dict[str, set[str]] = {}
|
|
39
|
+
|
|
40
|
+
# ------------------------------------------------------------------
|
|
41
|
+
# Public API (overrides)
|
|
42
|
+
# ------------------------------------------------------------------
|
|
54
43
|
def add_object(self, obj: Any, path: str = "root") -> None:
|
|
55
|
-
"""
|
|
56
|
-
Adds an object to the builder with format detection.
|
|
57
|
-
|
|
58
|
-
Args:
|
|
59
|
-
obj: Object to add
|
|
60
|
-
path: Path to the object (for internal use)
|
|
61
|
-
"""
|
|
62
|
-
# Call the parent method first
|
|
63
44
|
super().add_object(obj)
|
|
45
|
+
if self._format_mode != "off":
|
|
46
|
+
self._collect_formats(obj, path)
|
|
64
47
|
|
|
65
|
-
|
|
66
|
-
|
|
48
|
+
def to_schema(self) -> Dict[str, Any]:
|
|
49
|
+
schema = dict(super().to_schema()) # shallow‑copy
|
|
50
|
+
|
|
51
|
+
if self._format_mode != "off":
|
|
52
|
+
self._inject_formats(schema, "root")
|
|
53
|
+
|
|
54
|
+
if self._format_mode == "safe":
|
|
55
|
+
schema.setdefault(
|
|
56
|
+
"$vocabulary",
|
|
57
|
+
{
|
|
58
|
+
"https://json-schema.org/draft/2020-12/vocab/core": True,
|
|
59
|
+
"https://json-schema.org/draft/2020-12/vocab/applicator": True,
|
|
60
|
+
"https://json-schema.org/draft/2020-12/vocab/format-annotation": True,
|
|
61
|
+
"https://json-schema.org/draft/2020-12/vocab/format-assertion": False,
|
|
62
|
+
},
|
|
63
|
+
)
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
return schema
|
|
66
|
+
|
|
67
|
+
# ------------------------------------------------------------------
|
|
68
|
+
# Internals
|
|
69
|
+
# ------------------------------------------------------------------
|
|
70
|
+
def _collect_formats(self, obj: Any, path: str) -> None:
|
|
70
71
|
if isinstance(obj, str):
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if path not in self._format_cache:
|
|
75
|
-
self._format_cache[path] = set()
|
|
76
|
-
self._format_cache[path].add(detected_format)
|
|
72
|
+
fmt = FormatDetector.detect_format(obj)
|
|
73
|
+
if fmt:
|
|
74
|
+
self._format_cache.setdefault(path, set()).add(fmt)
|
|
77
75
|
elif isinstance(obj, dict):
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
self._process_formats(value, f"{path}.{key}")
|
|
76
|
+
for k, v in obj.items():
|
|
77
|
+
self._collect_formats(v, f"{path}.{k}")
|
|
81
78
|
elif isinstance(obj, (list, tuple)):
|
|
82
|
-
# Recursively process the list
|
|
83
79
|
for i, item in enumerate(obj):
|
|
84
|
-
self.
|
|
85
|
-
|
|
86
|
-
def
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
elif schema.get("type") == "object" and "properties" in schema:
|
|
104
|
-
# Recursively process the object properties
|
|
105
|
-
for prop_name, prop_schema in schema["properties"].items():
|
|
106
|
-
self._add_formats_to_schema(prop_schema, f"{path}.{prop_name}")
|
|
107
|
-
|
|
108
|
-
elif schema.get("type") == "array" and "items" in schema:
|
|
109
|
-
# Process the array items
|
|
110
|
-
if isinstance(schema["items"], dict):
|
|
111
|
-
self._add_formats_to_schema(schema["items"], f"{path}[0]")
|
|
112
|
-
elif isinstance(schema["items"], list):
|
|
113
|
-
for i, item_schema in enumerate(schema["items"]):
|
|
114
|
-
self._add_formats_to_schema(item_schema, f"{path}[{i}]")
|
|
115
|
-
|
|
80
|
+
self._collect_formats(item, f"{path}[{i}]")
|
|
81
|
+
|
|
82
|
+
def _inject_formats(self, schema: Dict[str, Any], path: str) -> None:
|
|
83
|
+
t = schema.get("type")
|
|
84
|
+
if t == "string":
|
|
85
|
+
fmts = self._format_cache.get(path)
|
|
86
|
+
if fmts and len(fmts) == 1:
|
|
87
|
+
schema["format"] = next(iter(fmts))
|
|
88
|
+
elif t == "object" and "properties" in schema:
|
|
89
|
+
for name, subschema in schema["properties"].items():
|
|
90
|
+
self._inject_formats(subschema, f"{path}.{name}")
|
|
91
|
+
elif t == "array" and "items" in schema:
|
|
92
|
+
items_schema = schema["items"]
|
|
93
|
+
if isinstance(items_schema, dict):
|
|
94
|
+
self._inject_formats(items_schema, f"{path}[0]")
|
|
95
|
+
else:
|
|
96
|
+
for idx, subschema in enumerate(items_schema):
|
|
97
|
+
self._inject_formats(subschema, f"{path}[{idx}]")
|
|
116
98
|
elif "anyOf" in schema:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
self._add_formats_to_schema(sub_schema, path)
|
|
99
|
+
for subschema in schema["anyOf"]:
|
|
100
|
+
self._inject_formats(subschema, path)
|
{pytest_jsonschema_snapshot-0.2.0.dist-info → pytest_jsonschema_snapshot-0.2.1.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-jsonschema-snapshot
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Pytest plugin for automatic JSON Schema generation and validation from examples
|
|
5
5
|
Project-URL: Homepage, https://miskler.github.io/pytest-jsonschema-snapshot/basic/quick_start.html
|
|
6
6
|
Project-URL: Repository, https://github.com/Miskler/pytest-jsonschema-snapshot
|
|
@@ -117,12 +117,12 @@ pip install pytest-jsonschema-snapshot
|
|
|
117
117
|
)
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
2. On first run, generate schemas with the `--schema-update` flag
|
|
120
|
+
2. On first run, generate schemas with the `--schema-update` or `--schema-reset` (what is the difference? see the documentation) flag
|
|
121
121
|
```bash
|
|
122
122
|
pytest --schema-update --save-original
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
**--save-original**: save the original data on which the validation was performed. Saving occurs when `--schema-update`, if you run the schema update without this attribute, the old original data will be deleted without saving new ones.
|
|
125
|
+
**--save-original**: save the original data on which the validation was performed. Saving occurs when `--schema-update` or `--schema-reset`, if you run the schema update without this attribute, the old original data will be deleted without saving new ones.
|
|
126
126
|
|
|
127
127
|
3. On subsequent runs, tests will validate data against saved schemas
|
|
128
128
|
```bash
|
{pytest_jsonschema_snapshot-0.2.0.dist-info → pytest_jsonschema_snapshot-0.2.1.dist-info}/RECORD
RENAMED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
pytest_jsonschema_snapshot/__init__.py,sha256=
|
|
2
|
-
pytest_jsonschema_snapshot/core.py,sha256=
|
|
3
|
-
pytest_jsonschema_snapshot/plugin.py,sha256=
|
|
1
|
+
pytest_jsonschema_snapshot/__init__.py,sha256=A3cUmyPftYWT68KRDu3V6WNGuIKdkqCtxYQS3eyPwbk,385
|
|
2
|
+
pytest_jsonschema_snapshot/core.py,sha256=951wNZ6BiVToaK8l-l5hgj8WPePBTSK5bDZqFOAZztg,11399
|
|
3
|
+
pytest_jsonschema_snapshot/plugin.py,sha256=nvAfxtLSX_B5FzaWu7DfsiWRxFjxDvnQNNOhkRrRnbw,8677
|
|
4
4
|
pytest_jsonschema_snapshot/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
pytest_jsonschema_snapshot/stats.py,sha256=XGGzHY0ytMFOkFpnqNAK1DpV9iI0_fZPWrVvHFNFL3g,7943
|
|
6
6
|
pytest_jsonschema_snapshot/tools/__init__.py,sha256=WMS6PdgMABBfTRhPGuoUOXB-R2PcqcadwH8pG1C6MFU,132
|
|
7
7
|
pytest_jsonschema_snapshot/tools/name_maker.py,sha256=tqss8NCGSo2aQX_-RkCJzy3NJx_TDA-xrn8qsblecf0,5799
|
|
8
8
|
pytest_jsonschema_snapshot/tools/genson_addon/__init__.py,sha256=nANkqHTaWTZPwBDztsnQvObHUZLSeHenJS--oWfep8c,92
|
|
9
9
|
pytest_jsonschema_snapshot/tools/genson_addon/format_detector.py,sha256=Wc5pB_xstyr4OtjwJ2qqmV62xET63cN7Nb0gxkrYyW0,1636
|
|
10
|
-
pytest_jsonschema_snapshot/tools/genson_addon/to_schema_converter.py,sha256=
|
|
11
|
-
pytest_jsonschema_snapshot-0.2.
|
|
12
|
-
pytest_jsonschema_snapshot-0.2.
|
|
13
|
-
pytest_jsonschema_snapshot-0.2.
|
|
14
|
-
pytest_jsonschema_snapshot-0.2.
|
|
15
|
-
pytest_jsonschema_snapshot-0.2.
|
|
10
|
+
pytest_jsonschema_snapshot/tools/genson_addon/to_schema_converter.py,sha256=UdQIkZhMrTJNHwI1B1dv3aEwx41B1B_lLyr4KWiUpNY,4168
|
|
11
|
+
pytest_jsonschema_snapshot-0.2.1.dist-info/METADATA,sha256=sKa-GvRU2__0rk-bOFpPhaIT7_gnZvkJX15AWRvkkl4,7657
|
|
12
|
+
pytest_jsonschema_snapshot-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
+
pytest_jsonschema_snapshot-0.2.1.dist-info/entry_points.txt,sha256=eJ1x4TMmhcc8YtM7IoCsUJO4-rLeTrGy8tPgkrojjKs,58
|
|
14
|
+
pytest_jsonschema_snapshot-0.2.1.dist-info/licenses/LICENSE,sha256=1HRFdSzlJ4BtHv6U7tZun3iCArjbCnm5NUowE9hZpNs,1071
|
|
15
|
+
pytest_jsonschema_snapshot-0.2.1.dist-info/RECORD,,
|
{pytest_jsonschema_snapshot-0.2.0.dist-info → pytest_jsonschema_snapshot-0.2.1.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|