genschema 0.1.0__tar.gz → 0.1.1__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.
- {genschema-0.1.0 → genschema-0.1.1}/PKG-INFO +1 -1
- {genschema-0.1.0 → genschema-0.1.1}/genschema/__init__.py +1 -1
- {genschema-0.1.0 → genschema-0.1.1}/genschema/cli.py +8 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/comparators/__init__.py +2 -0
- genschema-0.1.1/genschema/comparators/required.py +57 -0
- genschema-0.1.1/genschema/comparators/schema_version.py +18 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/pipeline.py +5 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema.egg-info/PKG-INFO +1 -1
- {genschema-0.1.0 → genschema-0.1.1}/genschema.egg-info/SOURCES.txt +1 -0
- genschema-0.1.0/genschema/comparators/required.py +0 -38
- {genschema-0.1.0 → genschema-0.1.1}/LICENSE +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/README.md +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/comparators/delete_element.py +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/comparators/empty.py +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/comparators/flag.py +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/comparators/format.py +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/comparators/no_additional_prop.py +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/comparators/template.py +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/comparators/type.py +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/node.py +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/pseudo_arrays.py +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema/py.typed +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema.egg-info/dependency_links.txt +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema.egg-info/entry_points.txt +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema.egg-info/requires.txt +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/genschema.egg-info/top_level.txt +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/pyproject.toml +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/setup.cfg +0 -0
- {genschema-0.1.0 → genschema-0.1.1}/tests/test_check_datasets.py +0 -0
|
@@ -11,6 +11,7 @@ from .comparators import (
|
|
|
11
11
|
EmptyComparator,
|
|
12
12
|
FormatComparator,
|
|
13
13
|
RequiredComparator,
|
|
14
|
+
SchemaVersionComparator,
|
|
14
15
|
)
|
|
15
16
|
|
|
16
17
|
console = Console()
|
|
@@ -52,6 +53,11 @@ Examples:
|
|
|
52
53
|
parser.add_argument("--no-format", action="store_true", help="Disable FormatComparator.")
|
|
53
54
|
parser.add_argument("--no-required", action="store_true", help="Disable RequiredComparator.")
|
|
54
55
|
parser.add_argument("--no-empty", action="store_true", help="Disable EmptyComparator.")
|
|
56
|
+
parser.add_argument(
|
|
57
|
+
"--no-schema-version",
|
|
58
|
+
action="store_true",
|
|
59
|
+
help="Disable SchemaVersionComparator.",
|
|
60
|
+
)
|
|
55
61
|
parser.add_argument(
|
|
56
62
|
"--no-delete-element", action="store_true", help="Disable DeleteElement comparators."
|
|
57
63
|
)
|
|
@@ -108,6 +114,8 @@ Examples:
|
|
|
108
114
|
# Register comparators conditionally
|
|
109
115
|
if not args.no_format:
|
|
110
116
|
conv.register(FormatComparator())
|
|
117
|
+
if not args.no_schema_version:
|
|
118
|
+
conv.register(SchemaVersionComparator())
|
|
111
119
|
if not args.no_required:
|
|
112
120
|
conv.register(RequiredComparator())
|
|
113
121
|
if not args.no_empty:
|
|
@@ -4,6 +4,7 @@ from .flag import FlagMaker
|
|
|
4
4
|
from .format import FormatComparator
|
|
5
5
|
from .no_additional_prop import NoAdditionalProperties
|
|
6
6
|
from .required import RequiredComparator
|
|
7
|
+
from .schema_version import SchemaVersionComparator
|
|
7
8
|
from .type import TypeComparator
|
|
8
9
|
|
|
9
10
|
__all__ = [
|
|
@@ -14,4 +15,5 @@ __all__ = [
|
|
|
14
15
|
"EmptyComparator",
|
|
15
16
|
"NoAdditionalProperties",
|
|
16
17
|
"DeleteElement",
|
|
18
|
+
"SchemaVersionComparator",
|
|
17
19
|
]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from .template import Comparator, ComparatorResult, ProcessingContext
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RequiredComparator(Comparator):
|
|
9
|
+
"""
|
|
10
|
+
Компаратор для определения обязательных полей.
|
|
11
|
+
Устанавливает "required" на основе наличия ключей в JSON на текущем уровне.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def can_process(self, ctx: ProcessingContext, env: str, node: dict) -> bool:
|
|
15
|
+
# обрабатываем только объекты
|
|
16
|
+
return (
|
|
17
|
+
(node.get("type") == "object" and not node.get("isPseudoArray", False))
|
|
18
|
+
or node.get("type") is None
|
|
19
|
+
or not ctx.jsons
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
def process(self, ctx: ProcessingContext, env: str, node: dict) -> ComparatorResult:
|
|
23
|
+
required_sets: list[set[str]] = []
|
|
24
|
+
|
|
25
|
+
# Если есть хотя бы один JSON, который не является объектом,
|
|
26
|
+
# мы не можем корректно определить обязательные ключи.
|
|
27
|
+
if ctx.jsons and any(not isinstance(j.content, dict) for j in ctx.jsons):
|
|
28
|
+
return None, None
|
|
29
|
+
|
|
30
|
+
# ---------- из json ----------
|
|
31
|
+
objects = [j.content for j in ctx.jsons if isinstance(j.content, dict)]
|
|
32
|
+
if objects:
|
|
33
|
+
keys: set[str] = set()
|
|
34
|
+
for obj in objects:
|
|
35
|
+
keys.update(obj.keys())
|
|
36
|
+
|
|
37
|
+
required_from_json = {k for k in keys if all(k in obj for obj in objects)}
|
|
38
|
+
required_sets.append(required_from_json)
|
|
39
|
+
|
|
40
|
+
# ---------- из схем ----------
|
|
41
|
+
for schema in ctx.schemas:
|
|
42
|
+
content = schema.content
|
|
43
|
+
if not isinstance(content, dict):
|
|
44
|
+
continue
|
|
45
|
+
req = content.get("required")
|
|
46
|
+
if isinstance(req, list):
|
|
47
|
+
required_sets.append(set(req))
|
|
48
|
+
|
|
49
|
+
if not required_sets:
|
|
50
|
+
return None, None
|
|
51
|
+
|
|
52
|
+
# ---------- минимальное пересечение ----------
|
|
53
|
+
required = sorted(set.intersection(*required_sets))
|
|
54
|
+
|
|
55
|
+
if required:
|
|
56
|
+
return {"required": required}, None
|
|
57
|
+
return None, None
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from .template import Comparator, ComparatorResult, ProcessingContext
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class SchemaVersionComparator(Comparator):
|
|
5
|
+
"""
|
|
6
|
+
Компаратор для установки версии JSON Schema на верхнем уровне.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
name = "schema_version"
|
|
10
|
+
|
|
11
|
+
def __init__(self, version: str = "https://json-schema.org/draft/2020-12/schema"):
|
|
12
|
+
self._version = version
|
|
13
|
+
|
|
14
|
+
def can_process(self, ctx: ProcessingContext, env: str, prev_result: dict) -> bool:
|
|
15
|
+
return env == "/" and "$schema" not in prev_result
|
|
16
|
+
|
|
17
|
+
def process(self, ctx: ProcessingContext, env: str, prev_result: dict) -> ComparatorResult:
|
|
18
|
+
return {"$schema": self._version}, None
|
|
@@ -57,6 +57,11 @@ class Converter:
|
|
|
57
57
|
self._jsons.append(Resource(str(self._id), "json", j))
|
|
58
58
|
self._id += 1
|
|
59
59
|
|
|
60
|
+
def clear_data(self) -> None:
|
|
61
|
+
self._id = 0
|
|
62
|
+
self._jsons = []
|
|
63
|
+
self._schemas = []
|
|
64
|
+
|
|
60
65
|
def register(self, c: Comparator) -> None:
|
|
61
66
|
if isinstance(c, TypeComparator):
|
|
62
67
|
raise UserWarning(
|
|
@@ -20,6 +20,7 @@ genschema/comparators/flag.py
|
|
|
20
20
|
genschema/comparators/format.py
|
|
21
21
|
genschema/comparators/no_additional_prop.py
|
|
22
22
|
genschema/comparators/required.py
|
|
23
|
+
genschema/comparators/schema_version.py
|
|
23
24
|
genschema/comparators/template.py
|
|
24
25
|
genschema/comparators/type.py
|
|
25
26
|
tests/test_check_datasets.py
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
from .template import Comparator, ComparatorResult, ProcessingContext
|
|
4
|
-
|
|
5
|
-
logger = logging.getLogger(__name__)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class RequiredComparator(Comparator):
|
|
9
|
-
"""
|
|
10
|
-
Компаратор для определения обязательных полей.
|
|
11
|
-
Устанавливает "required" на основе наличия ключей в JSON на текущем уровне.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
def can_process(self, ctx: ProcessingContext, env: str, node: dict) -> bool:
|
|
15
|
-
# обрабатываем только объекты
|
|
16
|
-
return (
|
|
17
|
-
(node.get("type") == "object" and not node.get("isPseudoArray", False))
|
|
18
|
-
or node.get("type") is None
|
|
19
|
-
or not ctx.jsons
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
def process(self, ctx: ProcessingContext, env: str, node: dict) -> ComparatorResult:
|
|
23
|
-
# собираем все ключи в JSON на этом уровне
|
|
24
|
-
keys: set[str] = set()
|
|
25
|
-
for j in ctx.jsons:
|
|
26
|
-
if isinstance(j.content, dict):
|
|
27
|
-
keys.update(j.content.keys())
|
|
28
|
-
|
|
29
|
-
# определяем обязательные: ключи, которые есть во всех JSON
|
|
30
|
-
required = [
|
|
31
|
-
k
|
|
32
|
-
for k in sorted(keys)
|
|
33
|
-
if all(isinstance(j.content, dict) and k in j.content for j in ctx.jsons)
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
-
if required:
|
|
37
|
-
return {"required": required}, None
|
|
38
|
-
return None, None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|