pytest-jsonschema-snapshot 0.2.3__tar.gz → 0.2.5__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.
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/PKG-INFO +2 -2
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/pyproject.toml +1 -1
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/pytest_jsonschema_snapshot/__init__.py +1 -1
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/pytest_jsonschema_snapshot/core.py +27 -12
- pytest_jsonschema_snapshot-0.2.5/pytest_jsonschema_snapshot/stats.py +225 -0
- pytest_jsonschema_snapshot-0.2.5/pytest_jsonschema_snapshot/tools/__init__.py +3 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/requirements.txt +1 -1
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/TestDataClass.get_data.first.schema.json +15 -15
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/TestDataClass.get_data.schema.json +15 -15
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/array_formats_test.schema.json +11 -11
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/date_test.schema.json +6 -6
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/datetime_test.schema.json +6 -6
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/email_test.schema.json +8 -8
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/get_data.first.schema.json +15 -15
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/get_data.schema.json +15 -15
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/ipv4_test.schema.json +8 -8
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/mixed_formats_test.schema.json +20 -20
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/regular_strings_test.schema.json +9 -9
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/some_schema.schema.json +72 -103
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/strict_email_validation_test.schema.json +5 -5
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/uri_test.schema.json +8 -8
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/uuid_test.schema.json +6 -6
- pytest_jsonschema_snapshot-0.2.5/tt.py +183 -0
- pytest_jsonschema_snapshot-0.2.5/yy.py +138 -0
- pytest_jsonschema_snapshot-0.2.3/pytest_jsonschema_snapshot/stats.py +0 -185
- pytest_jsonschema_snapshot-0.2.3/pytest_jsonschema_snapshot/tools/__init__.py +0 -4
- pytest_jsonschema_snapshot-0.2.3/pytest_jsonschema_snapshot/tools/genson_addon/__init__.py +0 -3
- pytest_jsonschema_snapshot-0.2.3/pytest_jsonschema_snapshot/tools/genson_addon/format_detector.py +0 -52
- pytest_jsonschema_snapshot-0.2.3/pytest_jsonschema_snapshot/tools/genson_addon/to_schema_converter.py +0 -100
- pytest_jsonschema_snapshot-0.2.3/tests/tools/genson_addon/test_format_safe.py +0 -82
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.flake8 +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.github/ISSUE_TEMPLATE/documentation_issue.yml +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.github/PULL_REQUEST_TEMPLATE/general.md +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.github/actions/build-docs/action.yml +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.github/workflows/release.yml +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.github/workflows/reusable-test.yml +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.github/workflows/test.yml +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/.gitignore +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/LICENSE +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/Makefile +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/README.md +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/assets/logo.png +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/docs/source/_static/logo_day.png +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/docs/source/_static/logo_night.png +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/docs/source/basic/quick_start.rst +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/docs/source/conf.py +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/docs/source/index.rst +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/pytest_jsonschema_snapshot/plugin.py +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/pytest_jsonschema_snapshot/py.typed +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/pytest_jsonschema_snapshot/tools/name_maker.py +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/reinstall_plugin.sh +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/test_stats.py +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/tools/test_name_maker.py +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/TestDataClass.get_data.first.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/TestDataClass.get_data.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/array_formats_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/date_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/datetime_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/email_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/get_data.first.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/get_data.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/ipv4_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/mixed_formats_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/multi_schema_one.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/multi_schema_three.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/multi_schema_two.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/regular_strings_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/some_schema.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/strict_email_validation_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/uri_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/__snapshots__/uuid_test.json +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/test_base.py +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/test_base_name_callable.py +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/test_format_detection.py +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/test_format_validation.py +0 -0
- {pytest_jsonschema_snapshot-0.2.3 → pytest_jsonschema_snapshot-0.2.5}/tests/usage/test_multiple_schema_creation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-jsonschema-snapshot
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
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
|
|
@@ -22,7 +22,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
22
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
23
|
Classifier: Topic :: Utilities
|
|
24
24
|
Requires-Python: >=3.10
|
|
25
|
-
Requires-Dist:
|
|
25
|
+
Requires-Dist: genschema
|
|
26
26
|
Requires-Dist: jsonschema
|
|
27
27
|
Requires-Dist: jsonschema-diff
|
|
28
28
|
Requires-Dist: pathvalidate
|
|
@@ -13,10 +13,17 @@ if TYPE_CHECKING:
|
|
|
13
13
|
from jsonschema_diff import JsonSchemaDiff
|
|
14
14
|
|
|
15
15
|
import pytest
|
|
16
|
+
from genschema import Converter, PseudoArrayHandler
|
|
17
|
+
from genschema.comparators import (
|
|
18
|
+
DeleteElement,
|
|
19
|
+
FormatComparator,
|
|
20
|
+
RequiredComparator,
|
|
21
|
+
SchemaVersionComparator,
|
|
22
|
+
)
|
|
16
23
|
from jsonschema import FormatChecker, ValidationError, validate
|
|
17
24
|
|
|
18
25
|
from .stats import GLOBAL_STATS
|
|
19
|
-
from .tools import
|
|
26
|
+
from .tools import NameMaker
|
|
20
27
|
|
|
21
28
|
|
|
22
29
|
class SchemaShot:
|
|
@@ -54,6 +61,17 @@ class SchemaShot:
|
|
|
54
61
|
self.snapshot_dir: Path = root_dir / snapshot_dir_name
|
|
55
62
|
self.used_schemas: Set[str] = set()
|
|
56
63
|
|
|
64
|
+
self.conv = Converter(
|
|
65
|
+
pseudo_handler=PseudoArrayHandler(),
|
|
66
|
+
base_of="anyOf",
|
|
67
|
+
)
|
|
68
|
+
self.conv.register(FormatComparator())
|
|
69
|
+
self.conv.register(RequiredComparator())
|
|
70
|
+
# self.conv.register(EmptyComparator())
|
|
71
|
+
self.conv.register(SchemaVersionComparator())
|
|
72
|
+
self.conv.register(DeleteElement())
|
|
73
|
+
self.conv.register(DeleteElement("isPseudoArray"))
|
|
74
|
+
|
|
57
75
|
self.logger = logging.getLogger(__name__)
|
|
58
76
|
# добавляем вывод в stderr
|
|
59
77
|
handler = logging.StreamHandler()
|
|
@@ -144,11 +162,9 @@ class SchemaShot:
|
|
|
144
162
|
|
|
145
163
|
real_name = self._process_name(name)
|
|
146
164
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
builder.add_object(data)
|
|
151
|
-
current_schema = builder.to_schema()
|
|
165
|
+
self.conv.clear_data()
|
|
166
|
+
self.conv.add_schema(data)
|
|
167
|
+
current_schema = self.conv.run()
|
|
152
168
|
|
|
153
169
|
real_name, status = self._base_match(data, current_schema, real_name)
|
|
154
170
|
|
|
@@ -234,12 +250,11 @@ class SchemaShot:
|
|
|
234
250
|
schema_updated = False
|
|
235
251
|
|
|
236
252
|
def merge_schemas(old: dict, new: dict) -> dict:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
return builder.to_schema()
|
|
253
|
+
self.conv.clear_data()
|
|
254
|
+
self.conv.add_schema(old)
|
|
255
|
+
self.conv.add_schema(new)
|
|
256
|
+
result = self.conv.run()
|
|
257
|
+
return result
|
|
243
258
|
|
|
244
259
|
if existing_schema != current_schema: # есть отличия
|
|
245
260
|
if (self.update_mode or self.reset_mode) and self.update_actions.get("update"):
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for collecting and displaying statistics about schemas.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Dict, Generator, List, Optional
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SchemaStats:
|
|
11
|
+
"""Class for collecting and displaying statistics about schemas"""
|
|
12
|
+
|
|
13
|
+
def __init__(self) -> None:
|
|
14
|
+
self.created: List[str] = []
|
|
15
|
+
self.updated: List[str] = []
|
|
16
|
+
self.updated_diffs: Dict[str, str] = {} # schema_name -> diff
|
|
17
|
+
self.uncommitted: List[str] = [] # New category for uncommitted changes
|
|
18
|
+
self.uncommitted_diffs: Dict[str, str] = {} # schema_name -> diff
|
|
19
|
+
self.deleted: List[str] = []
|
|
20
|
+
self.unused: List[str] = []
|
|
21
|
+
|
|
22
|
+
def add_created(self, schema_name: str) -> None:
|
|
23
|
+
"""Adds created schema"""
|
|
24
|
+
self.created.append(schema_name)
|
|
25
|
+
|
|
26
|
+
def add_updated(self, schema_name: str, diff: Optional[str] = None) -> None:
|
|
27
|
+
"""Adds updated schema"""
|
|
28
|
+
# Generate diff if both schemas are provided
|
|
29
|
+
if diff and diff.strip():
|
|
30
|
+
self.updated.append(schema_name)
|
|
31
|
+
self.updated_diffs[schema_name] = diff
|
|
32
|
+
else:
|
|
33
|
+
# If schemas are not provided, assume it was an update
|
|
34
|
+
self.updated.append(schema_name)
|
|
35
|
+
|
|
36
|
+
def add_uncommitted(self, schema_name: str, diff: Optional[str] = None) -> None:
|
|
37
|
+
"""Adds schema with uncommitted changes"""
|
|
38
|
+
# Add only if there are real changes
|
|
39
|
+
if diff and diff.strip():
|
|
40
|
+
self.uncommitted.append(schema_name)
|
|
41
|
+
self.uncommitted_diffs[schema_name] = diff
|
|
42
|
+
|
|
43
|
+
def add_deleted(self, schema_name: str) -> None:
|
|
44
|
+
"""Adds deleted schema"""
|
|
45
|
+
self.deleted.append(schema_name)
|
|
46
|
+
|
|
47
|
+
def add_unused(self, schema_name: str) -> None:
|
|
48
|
+
"""Adds unused schema"""
|
|
49
|
+
self.unused.append(schema_name)
|
|
50
|
+
|
|
51
|
+
def has_changes(self) -> bool:
|
|
52
|
+
"""Returns True if any schema has changes"""
|
|
53
|
+
return bool(self.created or self.updated or self.deleted)
|
|
54
|
+
|
|
55
|
+
def has_any_info(self) -> bool:
|
|
56
|
+
"""Is there any information about schemas"""
|
|
57
|
+
return bool(self.created or self.updated or self.deleted or self.unused or self.uncommitted)
|
|
58
|
+
|
|
59
|
+
def __str__(self) -> str:
|
|
60
|
+
parts = []
|
|
61
|
+
if self.created:
|
|
62
|
+
parts.append(
|
|
63
|
+
f"Created schemas ({len(self.created)}): "
|
|
64
|
+
+ ", ".join(f"`{s}`" for s in self.created)
|
|
65
|
+
)
|
|
66
|
+
if self.updated:
|
|
67
|
+
parts.append(
|
|
68
|
+
f"Updated schemas ({len(self.updated)}): "
|
|
69
|
+
+ ", ".join(f"`{s}`" for s in self.updated)
|
|
70
|
+
)
|
|
71
|
+
if self.deleted:
|
|
72
|
+
parts.append(
|
|
73
|
+
f"Deleted schemas ({len(self.deleted)}): "
|
|
74
|
+
+ ", ".join(f"`{s}`" for s in self.deleted)
|
|
75
|
+
)
|
|
76
|
+
if self.unused:
|
|
77
|
+
parts.append(
|
|
78
|
+
f"Unused schemas ({len(self.unused)}): " + ", ".join(f"`{s}`" for s in self.unused)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return "\n".join(parts)
|
|
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
|
+
|
|
130
|
+
def print_summary(self, terminalreporter: pytest.TerminalReporter, update_mode: bool) -> None:
|
|
131
|
+
"""
|
|
132
|
+
Prints schema summary to pytest terminal output.
|
|
133
|
+
Pairs of "<name>.schema.json" + "<name>.json" are merged into one line:
|
|
134
|
+
"<name>.schema.json + original" (if original is present).
|
|
135
|
+
Unpaired .json are shown in separate "only originals" sections.
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
if not self.has_any_info():
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
terminalreporter.write_sep("=", "Schema Summary")
|
|
142
|
+
|
|
143
|
+
# Created
|
|
144
|
+
if self.created:
|
|
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)
|
|
157
|
+
|
|
158
|
+
# Updated
|
|
159
|
+
if self.updated:
|
|
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)
|
|
185
|
+
|
|
186
|
+
# Uncommitted
|
|
187
|
+
if self.uncommitted:
|
|
188
|
+
terminalreporter.write_line(
|
|
189
|
+
f"Uncommitted minor updates ({len(self.uncommitted)}):", bold=True
|
|
190
|
+
)
|
|
191
|
+
for display, key in self._iter_schemas(self.uncommitted): # assuming mostly schemas
|
|
192
|
+
terminalreporter.write_line(f" - {display}", cyan=True)
|
|
193
|
+
# Show diff if available
|
|
194
|
+
if key and key in self.uncommitted_diffs:
|
|
195
|
+
terminalreporter.write_line(" Detected changes:", cyan=True)
|
|
196
|
+
for line in self.uncommitted_diffs[key].split("\n"):
|
|
197
|
+
if line.strip():
|
|
198
|
+
terminalreporter.write_line(f" {line}")
|
|
199
|
+
terminalreporter.write_line("") # separation
|
|
200
|
+
terminalreporter.write_line("Use --schema-update to commit these changes", cyan=True)
|
|
201
|
+
|
|
202
|
+
# Deleted
|
|
203
|
+
if self.deleted:
|
|
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)
|
|
218
|
+
if self.unused and not update_mode:
|
|
219
|
+
terminalreporter.write_line(f"Unused schemas ({len(self.unused)}):")
|
|
220
|
+
for display, _key in self._iter_schemas(self.unused): # assuming schemas
|
|
221
|
+
terminalreporter.write_line(f" - {display}")
|
|
222
|
+
terminalreporter.write_line("Use --schema-update to delete unused schemas", yellow=True)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
GLOBAL_STATS = SchemaStats()
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
2
|
"type": "object",
|
|
3
|
+
"required": [
|
|
4
|
+
"необязательная",
|
|
5
|
+
"обязательная",
|
|
6
|
+
"словарь"
|
|
7
|
+
],
|
|
8
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
9
|
"properties": {
|
|
5
|
-
"обязательная": {
|
|
6
|
-
"type": "string"
|
|
7
|
-
},
|
|
8
10
|
"необязательная": {
|
|
9
11
|
"type": "null"
|
|
10
12
|
},
|
|
13
|
+
"обязательная": {
|
|
14
|
+
"type": "string"
|
|
15
|
+
},
|
|
11
16
|
"словарь": {
|
|
12
17
|
"type": "object",
|
|
18
|
+
"required": [
|
|
19
|
+
"ключ",
|
|
20
|
+
"число"
|
|
21
|
+
],
|
|
13
22
|
"properties": {
|
|
14
23
|
"ключ": {
|
|
15
24
|
"type": "string"
|
|
@@ -17,16 +26,7 @@
|
|
|
17
26
|
"число": {
|
|
18
27
|
"type": "integer"
|
|
19
28
|
}
|
|
20
|
-
}
|
|
21
|
-
"required": [
|
|
22
|
-
"ключ",
|
|
23
|
-
"число"
|
|
24
|
-
]
|
|
29
|
+
}
|
|
25
30
|
}
|
|
26
|
-
}
|
|
27
|
-
"required": [
|
|
28
|
-
"необязательная",
|
|
29
|
-
"обязательная",
|
|
30
|
-
"словарь"
|
|
31
|
-
]
|
|
31
|
+
}
|
|
32
32
|
}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
2
|
"type": "object",
|
|
3
|
+
"required": [
|
|
4
|
+
"необязательная",
|
|
5
|
+
"обязательная",
|
|
6
|
+
"словарь"
|
|
7
|
+
],
|
|
8
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
9
|
"properties": {
|
|
5
|
-
"обязательная": {
|
|
6
|
-
"type": "string"
|
|
7
|
-
},
|
|
8
10
|
"необязательная": {
|
|
9
11
|
"type": "null"
|
|
10
12
|
},
|
|
13
|
+
"обязательная": {
|
|
14
|
+
"type": "string"
|
|
15
|
+
},
|
|
11
16
|
"словарь": {
|
|
12
17
|
"type": "object",
|
|
18
|
+
"required": [
|
|
19
|
+
"ключ",
|
|
20
|
+
"число"
|
|
21
|
+
],
|
|
13
22
|
"properties": {
|
|
14
23
|
"ключ": {
|
|
15
24
|
"type": "string"
|
|
@@ -17,16 +26,7 @@
|
|
|
17
26
|
"число": {
|
|
18
27
|
"type": "integer"
|
|
19
28
|
}
|
|
20
|
-
}
|
|
21
|
-
"required": [
|
|
22
|
-
"ключ",
|
|
23
|
-
"число"
|
|
24
|
-
]
|
|
29
|
+
}
|
|
25
30
|
}
|
|
26
|
-
}
|
|
27
|
-
"required": [
|
|
28
|
-
"необязательная",
|
|
29
|
-
"обязательная",
|
|
30
|
-
"словарь"
|
|
31
|
-
]
|
|
31
|
+
}
|
|
32
32
|
}
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
2
|
"type": "object",
|
|
3
|
+
"required": [
|
|
4
|
+
"dates",
|
|
5
|
+
"emails",
|
|
6
|
+
"uuids"
|
|
7
|
+
],
|
|
8
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
9
|
"properties": {
|
|
5
|
-
"
|
|
10
|
+
"dates": {
|
|
6
11
|
"type": "array",
|
|
7
12
|
"items": {
|
|
8
13
|
"type": "string",
|
|
9
|
-
"format": "
|
|
14
|
+
"format": "date"
|
|
10
15
|
}
|
|
11
16
|
},
|
|
12
|
-
"
|
|
17
|
+
"emails": {
|
|
13
18
|
"type": "array",
|
|
14
19
|
"items": {
|
|
15
20
|
"type": "string",
|
|
16
|
-
"format": "
|
|
21
|
+
"format": "email"
|
|
17
22
|
}
|
|
18
23
|
},
|
|
19
24
|
"uuids": {
|
|
@@ -23,10 +28,5 @@
|
|
|
23
28
|
"format": "uuid"
|
|
24
29
|
}
|
|
25
30
|
}
|
|
26
|
-
}
|
|
27
|
-
"required": [
|
|
28
|
-
"dates",
|
|
29
|
-
"emails",
|
|
30
|
-
"uuids"
|
|
31
|
-
]
|
|
31
|
+
}
|
|
32
32
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
2
|
"type": "object",
|
|
3
|
+
"required": [
|
|
4
|
+
"birth_date",
|
|
5
|
+
"registration_date"
|
|
6
|
+
],
|
|
7
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
8
|
"properties": {
|
|
5
9
|
"birth_date": {
|
|
6
10
|
"type": "string",
|
|
@@ -10,9 +14,5 @@
|
|
|
10
14
|
"type": "string",
|
|
11
15
|
"format": "date"
|
|
12
16
|
}
|
|
13
|
-
}
|
|
14
|
-
"required": [
|
|
15
|
-
"birth_date",
|
|
16
|
-
"registration_date"
|
|
17
|
-
]
|
|
17
|
+
}
|
|
18
18
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
2
|
"type": "object",
|
|
3
|
+
"required": [
|
|
4
|
+
"created_at",
|
|
5
|
+
"updated_at"
|
|
6
|
+
],
|
|
7
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
8
|
"properties": {
|
|
5
9
|
"created_at": {
|
|
6
10
|
"type": "string",
|
|
@@ -10,9 +14,5 @@
|
|
|
10
14
|
"type": "string",
|
|
11
15
|
"format": "date-time"
|
|
12
16
|
}
|
|
13
|
-
}
|
|
14
|
-
"required": [
|
|
15
|
-
"created_at",
|
|
16
|
-
"updated_at"
|
|
17
|
-
]
|
|
17
|
+
}
|
|
18
18
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
2
|
"type": "object",
|
|
3
|
+
"required": [
|
|
4
|
+
"admin_email",
|
|
5
|
+
"user_email"
|
|
6
|
+
],
|
|
7
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
8
|
"properties": {
|
|
5
|
-
"
|
|
9
|
+
"admin_email": {
|
|
6
10
|
"type": "string",
|
|
7
11
|
"format": "email"
|
|
8
12
|
},
|
|
9
|
-
"
|
|
13
|
+
"user_email": {
|
|
10
14
|
"type": "string",
|
|
11
15
|
"format": "email"
|
|
12
16
|
}
|
|
13
|
-
}
|
|
14
|
-
"required": [
|
|
15
|
-
"admin_email",
|
|
16
|
-
"user_email"
|
|
17
|
-
]
|
|
17
|
+
}
|
|
18
18
|
}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
2
|
"type": "object",
|
|
3
|
+
"required": [
|
|
4
|
+
"необязательная",
|
|
5
|
+
"обязательная",
|
|
6
|
+
"словарь"
|
|
7
|
+
],
|
|
8
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
9
|
"properties": {
|
|
5
|
-
"обязательная": {
|
|
6
|
-
"type": "string"
|
|
7
|
-
},
|
|
8
10
|
"необязательная": {
|
|
9
11
|
"type": "null"
|
|
10
12
|
},
|
|
13
|
+
"обязательная": {
|
|
14
|
+
"type": "string"
|
|
15
|
+
},
|
|
11
16
|
"словарь": {
|
|
12
17
|
"type": "object",
|
|
18
|
+
"required": [
|
|
19
|
+
"ключ",
|
|
20
|
+
"число"
|
|
21
|
+
],
|
|
13
22
|
"properties": {
|
|
14
23
|
"ключ": {
|
|
15
24
|
"type": "string"
|
|
@@ -17,16 +26,7 @@
|
|
|
17
26
|
"число": {
|
|
18
27
|
"type": "integer"
|
|
19
28
|
}
|
|
20
|
-
}
|
|
21
|
-
"required": [
|
|
22
|
-
"ключ",
|
|
23
|
-
"число"
|
|
24
|
-
]
|
|
29
|
+
}
|
|
25
30
|
}
|
|
26
|
-
}
|
|
27
|
-
"required": [
|
|
28
|
-
"необязательная",
|
|
29
|
-
"обязательная",
|
|
30
|
-
"словарь"
|
|
31
|
-
]
|
|
31
|
+
}
|
|
32
32
|
}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
2
|
"type": "object",
|
|
3
|
+
"required": [
|
|
4
|
+
"необязательная",
|
|
5
|
+
"обязательная",
|
|
6
|
+
"словарь"
|
|
7
|
+
],
|
|
8
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
9
|
"properties": {
|
|
5
|
-
"обязательная": {
|
|
6
|
-
"type": "string"
|
|
7
|
-
},
|
|
8
10
|
"необязательная": {
|
|
9
11
|
"type": "null"
|
|
10
12
|
},
|
|
13
|
+
"обязательная": {
|
|
14
|
+
"type": "string"
|
|
15
|
+
},
|
|
11
16
|
"словарь": {
|
|
12
17
|
"type": "object",
|
|
18
|
+
"required": [
|
|
19
|
+
"ключ",
|
|
20
|
+
"число"
|
|
21
|
+
],
|
|
13
22
|
"properties": {
|
|
14
23
|
"ключ": {
|
|
15
24
|
"type": "string"
|
|
@@ -17,16 +26,7 @@
|
|
|
17
26
|
"число": {
|
|
18
27
|
"type": "integer"
|
|
19
28
|
}
|
|
20
|
-
}
|
|
21
|
-
"required": [
|
|
22
|
-
"ключ",
|
|
23
|
-
"число"
|
|
24
|
-
]
|
|
29
|
+
}
|
|
25
30
|
}
|
|
26
|
-
}
|
|
27
|
-
"required": [
|
|
28
|
-
"необязательная",
|
|
29
|
-
"обязательная",
|
|
30
|
-
"словарь"
|
|
31
|
-
]
|
|
31
|
+
}
|
|
32
32
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
2
|
"type": "object",
|
|
3
|
+
"required": [
|
|
4
|
+
"gateway",
|
|
5
|
+
"server_ip"
|
|
6
|
+
],
|
|
7
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
8
|
"properties": {
|
|
5
|
-
"
|
|
9
|
+
"gateway": {
|
|
6
10
|
"type": "string",
|
|
7
11
|
"format": "ipv4"
|
|
8
12
|
},
|
|
9
|
-
"
|
|
13
|
+
"server_ip": {
|
|
10
14
|
"type": "string",
|
|
11
15
|
"format": "ipv4"
|
|
12
16
|
}
|
|
13
|
-
}
|
|
14
|
-
"required": [
|
|
15
|
-
"gateway",
|
|
16
|
-
"server_ip"
|
|
17
|
-
]
|
|
17
|
+
}
|
|
18
18
|
}
|