pytest-jsonschema-snapshot 0.2.2__py3-none-any.whl → 0.2.4__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 +15 -12
- pytest_jsonschema_snapshot/stats.py +103 -63
- {pytest_jsonschema_snapshot-0.2.2.dist-info → pytest_jsonschema_snapshot-0.2.4.dist-info}/METADATA +2 -1
- {pytest_jsonschema_snapshot-0.2.2.dist-info → pytest_jsonschema_snapshot-0.2.4.dist-info}/RECORD +8 -8
- {pytest_jsonschema_snapshot-0.2.2.dist-info → pytest_jsonschema_snapshot-0.2.4.dist-info}/WHEEL +0 -0
- {pytest_jsonschema_snapshot-0.2.2.dist-info → pytest_jsonschema_snapshot-0.2.4.dist-info}/entry_points.txt +0 -0
- {pytest_jsonschema_snapshot-0.2.2.dist-info → pytest_jsonschema_snapshot-0.2.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -233,6 +233,14 @@ class SchemaShot:
|
|
|
233
233
|
# --- схема уже была: сравнение и валидация --------------------------------
|
|
234
234
|
schema_updated = False
|
|
235
235
|
|
|
236
|
+
def merge_schemas(old: dict, new: dict) -> dict:
|
|
237
|
+
builder = JsonToSchemaConverter(
|
|
238
|
+
format_mode=self.format_mode # type: ignore[arg-type]
|
|
239
|
+
) # , examples=self.examples_limit)
|
|
240
|
+
builder.add_schema(old)
|
|
241
|
+
builder.add_schema(new)
|
|
242
|
+
return builder.to_schema()
|
|
243
|
+
|
|
236
244
|
if existing_schema != current_schema: # есть отличия
|
|
237
245
|
if (self.update_mode or self.reset_mode) and self.update_actions.get("update"):
|
|
238
246
|
# обновляем файл
|
|
@@ -246,12 +254,7 @@ class SchemaShot:
|
|
|
246
254
|
json.dump(current_schema, f, indent=2, ensure_ascii=False)
|
|
247
255
|
self.logger.warning(f"Schema `{name}` updated (reset).\n\n{differences}")
|
|
248
256
|
elif self.update_mode and not self.reset_mode:
|
|
249
|
-
|
|
250
|
-
format_mode=self.format_mode # type: ignore[arg-type]
|
|
251
|
-
) # , examples=self.examples_limit)
|
|
252
|
-
builder.add_schema(existing_schema)
|
|
253
|
-
builder.add_schema(current_schema)
|
|
254
|
-
merged_schema = builder.to_schema()
|
|
257
|
+
merged_schema = merge_schemas(existing_schema, current_schema)
|
|
255
258
|
|
|
256
259
|
differences = self.differ.compare(
|
|
257
260
|
dict(existing_schema), merged_schema
|
|
@@ -268,9 +271,9 @@ class SchemaShot:
|
|
|
268
271
|
)
|
|
269
272
|
schema_updated = True
|
|
270
273
|
elif data is not None:
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
).render()
|
|
274
|
+
merged_schema = merge_schemas(existing_schema, current_schema)
|
|
275
|
+
|
|
276
|
+
differences = self.differ.compare(dict(existing_schema), merged_schema).render()
|
|
274
277
|
GLOBAL_STATS.add_uncommitted(schema_path.name, differences)
|
|
275
278
|
|
|
276
279
|
# только валидируем по старой схеме
|
|
@@ -293,9 +296,9 @@ class SchemaShot:
|
|
|
293
296
|
format_checker=FormatChecker(),
|
|
294
297
|
)
|
|
295
298
|
except ValidationError as e:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
).render()
|
|
299
|
+
merged_schema = merge_schemas(existing_schema, current_schema)
|
|
300
|
+
|
|
301
|
+
differences = self.differ.compare(dict(existing_schema), merged_schema).render()
|
|
299
302
|
pytest.fail(f"\n\n{differences}\n\nValidation error in `{name}`: {e.message}")
|
|
300
303
|
|
|
301
304
|
return name, schema_updated
|
|
@@ -80,51 +80,61 @@ class SchemaStats:
|
|
|
80
80
|
|
|
81
81
|
return "\n".join(parts)
|
|
82
82
|
|
|
83
|
+
def _iter_schemas(self, names: List[str]) -> Generator[tuple[str, Optional[str]], None, None]:
|
|
84
|
+
"""
|
|
85
|
+
Iterates over schema displays: (display, schema_key)
|
|
86
|
+
- display: string to display (may have " + original")
|
|
87
|
+
- schema_key: file name of the schema (<name>.schema.json) to find diffs,
|
|
88
|
+
or None if it's not a schema.
|
|
89
|
+
Preserves the original list order: merging happens at .schema.json
|
|
90
|
+
position; skips .json if paired with schema.
|
|
91
|
+
"""
|
|
92
|
+
names = list(names) # order matters
|
|
93
|
+
schema_sfx = ".schema.json"
|
|
94
|
+
json_sfx = ".json"
|
|
95
|
+
|
|
96
|
+
# sets of bases
|
|
97
|
+
# bases_with_schema = {n[: -len(schema_sfx)] for n in names if n.endswith(schema_sfx)}
|
|
98
|
+
bases_with_original = {
|
|
99
|
+
n[: -len(json_sfx)]
|
|
100
|
+
for n in names
|
|
101
|
+
if n.endswith(json_sfx) and not n.endswith(schema_sfx)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for n in names:
|
|
105
|
+
if n.endswith(schema_sfx):
|
|
106
|
+
base = n[: -len(schema_sfx)]
|
|
107
|
+
if base in bases_with_original:
|
|
108
|
+
yield f"{n} + original", n # display, schema_key
|
|
109
|
+
else:
|
|
110
|
+
yield n, n
|
|
111
|
+
# if .json, skip if paired
|
|
112
|
+
# if other, yield n, n (but assume all are .json or .schema.json)
|
|
113
|
+
|
|
114
|
+
def _iter_only_originals(self, names: List[str]) -> Generator[str, None, None]:
|
|
115
|
+
"""
|
|
116
|
+
Iterates over only unpaired .json files, in the order they appear.
|
|
117
|
+
"""
|
|
118
|
+
names = list(names) # order matters
|
|
119
|
+
schema_sfx = ".schema.json"
|
|
120
|
+
json_sfx = ".json"
|
|
121
|
+
|
|
122
|
+
bases_with_schema = {n[: -len(schema_sfx)] for n in names if n.endswith(schema_sfx)}
|
|
123
|
+
|
|
124
|
+
for n in names:
|
|
125
|
+
if n.endswith(json_sfx) and not n.endswith(schema_sfx):
|
|
126
|
+
base = n[: -len(json_sfx)]
|
|
127
|
+
if base not in bases_with_schema:
|
|
128
|
+
yield n
|
|
129
|
+
|
|
83
130
|
def print_summary(self, terminalreporter: pytest.TerminalReporter, update_mode: bool) -> None:
|
|
84
131
|
"""
|
|
85
132
|
Prints schema summary to pytest terminal output.
|
|
86
133
|
Pairs of "<name>.schema.json" + "<name>.json" are merged into one line:
|
|
87
134
|
"<name>.schema.json + original" (if original is present).
|
|
135
|
+
Unpaired .json are shown in separate "only originals" sections.
|
|
88
136
|
"""
|
|
89
137
|
|
|
90
|
-
def _iter_merged(names: List[str]) -> Generator[tuple[str, Optional[str]], None, None]:
|
|
91
|
-
"""
|
|
92
|
-
Iterates over (display, schema_key):
|
|
93
|
-
- display: string to display (may have " + original")
|
|
94
|
-
- schema_key: file name of the schema (<name>.schema.json) to find diffs,
|
|
95
|
-
or None if it's not a schema.
|
|
96
|
-
Preserves the original list order: merging happens at .schema.json
|
|
97
|
-
position; single .json outputs are left as is.
|
|
98
|
-
"""
|
|
99
|
-
names = list(names) # порядок важен
|
|
100
|
-
schema_sfx = ".schema.json"
|
|
101
|
-
json_sfx = ".json"
|
|
102
|
-
|
|
103
|
-
# множество баз, где имеются схемы/оригиналы
|
|
104
|
-
bases_with_schema = {n[: -len(schema_sfx)] for n in names if n.endswith(schema_sfx)}
|
|
105
|
-
bases_with_original = {
|
|
106
|
-
n[: -len(json_sfx)]
|
|
107
|
-
for n in names
|
|
108
|
-
if n.endswith(json_sfx) and not n.endswith(schema_sfx)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
for n in names:
|
|
112
|
-
if n.endswith(schema_sfx):
|
|
113
|
-
base = n[: -len(schema_sfx)]
|
|
114
|
-
if base in bases_with_original:
|
|
115
|
-
yield f"{n} + original", n # display, schema_key
|
|
116
|
-
else:
|
|
117
|
-
yield n, n
|
|
118
|
-
elif n.endswith(json_sfx) and not n.endswith(schema_sfx):
|
|
119
|
-
base = n[: -len(json_sfx)]
|
|
120
|
-
# если есть парная схема — .json не выводим отдельно
|
|
121
|
-
if base in bases_with_schema:
|
|
122
|
-
continue
|
|
123
|
-
yield n, None
|
|
124
|
-
else:
|
|
125
|
-
# на всякий случай — прочие имена
|
|
126
|
-
yield n, n
|
|
127
|
-
|
|
128
138
|
if not self.has_any_info():
|
|
129
139
|
return
|
|
130
140
|
|
|
@@ -132,52 +142,82 @@ class SchemaStats:
|
|
|
132
142
|
|
|
133
143
|
# Created
|
|
134
144
|
if self.created:
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
145
|
+
schemas = list(self._iter_schemas(self.created))
|
|
146
|
+
only_originals = list(self._iter_only_originals(self.created))
|
|
147
|
+
if schemas:
|
|
148
|
+
terminalreporter.write_line(f"Created schemas ({len(schemas)}):", green=True)
|
|
149
|
+
for display, _key in schemas:
|
|
150
|
+
terminalreporter.write_line(f" - {display}", green=True)
|
|
151
|
+
if only_originals:
|
|
152
|
+
terminalreporter.write_line(
|
|
153
|
+
f"Created only originals ({len(only_originals)}):", green=True
|
|
154
|
+
)
|
|
155
|
+
for display in only_originals:
|
|
156
|
+
terminalreporter.write_line(f" - {display}", green=True)
|
|
138
157
|
|
|
139
158
|
# Updated
|
|
140
159
|
if self.updated:
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
terminalreporter.write_line("
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
schemas = list(self._iter_schemas(self.updated))
|
|
161
|
+
only_originals = list(self._iter_only_originals(self.updated))
|
|
162
|
+
if schemas:
|
|
163
|
+
terminalreporter.write_line(f"Updated schemas ({len(schemas)}):", yellow=True)
|
|
164
|
+
for display, key in schemas:
|
|
165
|
+
terminalreporter.write_line(f" - {display}", yellow=True)
|
|
166
|
+
# Show diff if available for schema
|
|
167
|
+
if key and key in self.updated_diffs:
|
|
168
|
+
diff = self.updated_diffs[key]
|
|
169
|
+
if diff.strip():
|
|
170
|
+
terminalreporter.write_line(" Changes:", yellow=True)
|
|
171
|
+
for line in diff.split("\n"):
|
|
172
|
+
if line.strip():
|
|
173
|
+
terminalreporter.write_line(f" {line}")
|
|
174
|
+
terminalreporter.write_line("") # separation
|
|
175
|
+
else:
|
|
176
|
+
terminalreporter.write_line(
|
|
177
|
+
" (Schema unchanged - no differences detected)", cyan=True
|
|
178
|
+
)
|
|
179
|
+
if only_originals:
|
|
180
|
+
terminalreporter.write_line(
|
|
181
|
+
f"Updated only originals ({len(only_originals)}):", yellow=True
|
|
182
|
+
)
|
|
183
|
+
for display in only_originals:
|
|
184
|
+
terminalreporter.write_line(f" - {display}", yellow=True)
|
|
155
185
|
|
|
156
186
|
# Uncommitted
|
|
157
187
|
if self.uncommitted:
|
|
158
188
|
terminalreporter.write_line(
|
|
159
189
|
f"Uncommitted minor updates ({len(self.uncommitted)}):", bold=True
|
|
160
190
|
)
|
|
161
|
-
for display, key in
|
|
191
|
+
for display, key in self._iter_schemas(self.uncommitted): # assuming mostly schemas
|
|
162
192
|
terminalreporter.write_line(f" - {display}", cyan=True)
|
|
193
|
+
# Show diff if available
|
|
163
194
|
if key and key in self.uncommitted_diffs:
|
|
164
195
|
terminalreporter.write_line(" Detected changes:", cyan=True)
|
|
165
196
|
for line in self.uncommitted_diffs[key].split("\n"):
|
|
166
197
|
if line.strip():
|
|
167
198
|
terminalreporter.write_line(f" {line}")
|
|
168
|
-
terminalreporter.write_line("") #
|
|
199
|
+
terminalreporter.write_line("") # separation
|
|
169
200
|
terminalreporter.write_line("Use --schema-update to commit these changes", cyan=True)
|
|
170
201
|
|
|
171
202
|
# Deleted
|
|
172
203
|
if self.deleted:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
204
|
+
schemas = list(self._iter_schemas(self.deleted))
|
|
205
|
+
only_originals = list(self._iter_only_originals(self.deleted))
|
|
206
|
+
if schemas:
|
|
207
|
+
terminalreporter.write_line(f"Deleted schemas ({len(schemas)}):", red=True)
|
|
208
|
+
for display, _key in schemas:
|
|
209
|
+
terminalreporter.write_line(f" - {display}", red=True)
|
|
210
|
+
if only_originals:
|
|
211
|
+
terminalreporter.write_line(
|
|
212
|
+
f"Deleted only originals ({len(only_originals)}):", red=True
|
|
213
|
+
)
|
|
214
|
+
for display in only_originals:
|
|
215
|
+
terminalreporter.write_line(f" - {display}", red=True)
|
|
216
|
+
|
|
217
|
+
# Unused (only if not update_mode)
|
|
178
218
|
if self.unused and not update_mode:
|
|
179
219
|
terminalreporter.write_line(f"Unused schemas ({len(self.unused)}):")
|
|
180
|
-
for display, _key in
|
|
220
|
+
for display, _key in self._iter_schemas(self.unused): # assuming schemas
|
|
181
221
|
terminalreporter.write_line(f" - {display}")
|
|
182
222
|
terminalreporter.write_line("Use --schema-update to delete unused schemas", yellow=True)
|
|
183
223
|
|
{pytest_jsonschema_snapshot-0.2.2.dist-info → pytest_jsonschema_snapshot-0.2.4.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.4
|
|
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
|
|
@@ -58,6 +58,7 @@ Description-Content-Type: text/markdown
|
|
|
58
58
|
[](https://pypi.org/project/pytest-jsonschema-snapshot/)
|
|
59
59
|
[](LICENSE)
|
|
60
60
|
[](https://github.com/psf/black)
|
|
61
|
+
[](https://pycqa.github.io/isort/)
|
|
61
62
|
[](https://mypy.readthedocs.io/en/stable/index.html)
|
|
62
63
|
[](https://discord.gg/UnJnGHNbBp)
|
|
63
64
|
[](https://t.me/miskler_dev)
|
{pytest_jsonschema_snapshot-0.2.2.dist-info → pytest_jsonschema_snapshot-0.2.4.dist-info}/RECORD
RENAMED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
pytest_jsonschema_snapshot/__init__.py,sha256=
|
|
2
|
-
pytest_jsonschema_snapshot/core.py,sha256=
|
|
1
|
+
pytest_jsonschema_snapshot/__init__.py,sha256=rUBgKVh7nCLEwfO0XZS-TewnM5eTXpBEI7NaC5p4qLg,385
|
|
2
|
+
pytest_jsonschema_snapshot/core.py,sha256=CoL_W-u6o3N7XDwv-MbePJiZaGX0LtGS6BLbj9MHROU,11995
|
|
3
3
|
pytest_jsonschema_snapshot/plugin.py,sha256=nvAfxtLSX_B5FzaWu7DfsiWRxFjxDvnQNNOhkRrRnbw,8677
|
|
4
4
|
pytest_jsonschema_snapshot/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
pytest_jsonschema_snapshot/stats.py,sha256=
|
|
5
|
+
pytest_jsonschema_snapshot/stats.py,sha256=BfhfMoSkRq6Q8BwhVfrpcFl5TP9OzpgpLwnKf1Kslkw,9593
|
|
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
10
|
pytest_jsonschema_snapshot/tools/genson_addon/to_schema_converter.py,sha256=UdQIkZhMrTJNHwI1B1dv3aEwx41B1B_lLyr4KWiUpNY,4168
|
|
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.
|
|
11
|
+
pytest_jsonschema_snapshot-0.2.4.dist-info/METADATA,sha256=iiGeO3N83BH1griTvads-RUawss1rw_9NIlFEdK6mkM,7795
|
|
12
|
+
pytest_jsonschema_snapshot-0.2.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
+
pytest_jsonschema_snapshot-0.2.4.dist-info/entry_points.txt,sha256=eJ1x4TMmhcc8YtM7IoCsUJO4-rLeTrGy8tPgkrojjKs,58
|
|
14
|
+
pytest_jsonschema_snapshot-0.2.4.dist-info/licenses/LICENSE,sha256=1HRFdSzlJ4BtHv6U7tZun3iCArjbCnm5NUowE9hZpNs,1071
|
|
15
|
+
pytest_jsonschema_snapshot-0.2.4.dist-info/RECORD,,
|
{pytest_jsonschema_snapshot-0.2.2.dist-info → pytest_jsonschema_snapshot-0.2.4.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|