Replace voluptuous with validx for schema validation
This commit is contained in:
Родитель
66a25fe39a
Коммит
ceab0279e7
|
@ -2,4 +2,4 @@
|
|||
multi_line_output=3
|
||||
include_trailing_comma=True
|
||||
line_length=88
|
||||
known_third_party = adr,appdirs,boto3,botocore,cachy,loguru,lru,pytest,requests,responses,taskcluster,taskcluster_urls,tomlkit,voluptuous,yaml,zstandard
|
||||
known_third_party = adr,appdirs,boto3,botocore,cachy,loguru,lru,pytest,requests,responses,taskcluster,taskcluster_urls,tomlkit,validx,yaml,zstandard
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from abc import ABC, abstractproperty
|
||||
from pprint import pprint
|
||||
from typing import Any, Dict, List, Tuple, Union
|
||||
|
||||
import voluptuous
|
||||
import validx
|
||||
from loguru import logger
|
||||
|
||||
from mozci.data.contract import all_contracts
|
||||
|
@ -82,21 +81,8 @@ class DataHandler:
|
|||
# Validate output.
|
||||
try:
|
||||
contract.validate_out(result)
|
||||
except voluptuous.MultipleInvalid as e:
|
||||
except validx.exc.SchemaError:
|
||||
print(f"Result from contract '{name}' does not conform to schema!")
|
||||
for error in e.errors:
|
||||
if not error.path:
|
||||
continue
|
||||
|
||||
problem = result
|
||||
for i in error.path[:-1]:
|
||||
problem = problem[i]
|
||||
|
||||
print(
|
||||
f'\nProblem with item "{error.path[-1]}" in the following object:'
|
||||
)
|
||||
pprint(problem, indent=2, depth=2)
|
||||
print()
|
||||
raise
|
||||
return result
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
from dataclasses import dataclass
|
||||
from textwrap import dedent
|
||||
from typing import Tuple
|
||||
from typing import Tuple, Union
|
||||
|
||||
from voluptuous import All, Any, Length, Marker, Optional, Required, Schema
|
||||
import validx as v
|
||||
|
||||
from mozci.task import TestTask
|
||||
|
||||
|
@ -13,46 +13,42 @@ from mozci.task import TestTask
|
|||
class Contract:
|
||||
name: str
|
||||
description: str
|
||||
validate_in: Schema
|
||||
validate_out: Schema
|
||||
validate_in: v.Dict
|
||||
validate_out: Union[v.Dict, v.List]
|
||||
|
||||
|
||||
_contracts: Tuple[Contract, ...] = (
|
||||
Contract(
|
||||
name="push_tasks",
|
||||
description="Data about the tasks that ran on a given push.",
|
||||
validate_in=Schema(
|
||||
validate_in=v.Dict(
|
||||
{
|
||||
Required("branch"): str,
|
||||
Required("rev"): str,
|
||||
"branch": v.Str(),
|
||||
"rev": v.Str(),
|
||||
}
|
||||
),
|
||||
validate_out=Schema(
|
||||
[
|
||||
validate_out=v.List(
|
||||
v.Dict(
|
||||
{
|
||||
Required("id"): str,
|
||||
Required("label"): str,
|
||||
Required("state"): Any(
|
||||
"completed",
|
||||
"running",
|
||||
"pending",
|
||||
"unscheduled",
|
||||
"id": v.Str(),
|
||||
"label": v.Str(),
|
||||
"state": v.Str(
|
||||
options=["completed", "running", "pending", "unscheduled"]
|
||||
),
|
||||
Required("tags"): {
|
||||
Marker(str, description="tag name"): Marker(
|
||||
str, description="tag value"
|
||||
)
|
||||
},
|
||||
Optional("duration"): int,
|
||||
Optional("result"): Any(
|
||||
"passed",
|
||||
"failed",
|
||||
"exception",
|
||||
"canceled",
|
||||
"superseded",
|
||||
"tags": v.Dict(extra=(v.Str(), v.Str())),
|
||||
"duration": v.Int(),
|
||||
"result": v.Str(
|
||||
options=[
|
||||
"passed",
|
||||
"failed",
|
||||
"exception",
|
||||
"canceled",
|
||||
"superseded",
|
||||
]
|
||||
),
|
||||
}
|
||||
]
|
||||
},
|
||||
optional=["duration", "result"],
|
||||
)
|
||||
),
|
||||
),
|
||||
Contract(
|
||||
|
@ -63,75 +59,73 @@ _contracts: Tuple[Contract, ...] = (
|
|||
without a classification need not be present.
|
||||
"""
|
||||
),
|
||||
validate_in=Schema(
|
||||
validate_in=v.Dict(
|
||||
{
|
||||
Required("branch"): str,
|
||||
Required("rev"): str,
|
||||
"branch": v.Str(),
|
||||
"rev": v.Str(),
|
||||
}
|
||||
),
|
||||
validate_out=Schema(
|
||||
{
|
||||
Marker(str, description="task id"): {
|
||||
Required("classification"): Any(
|
||||
"autoclassified intermittent",
|
||||
"infra",
|
||||
"intermittent",
|
||||
"expected fail",
|
||||
"fixed by commit",
|
||||
"not classified",
|
||||
),
|
||||
Optional("classification_note"): str,
|
||||
}
|
||||
}
|
||||
validate_out=v.Dict(
|
||||
extra=(
|
||||
v.Str(),
|
||||
v.Dict(
|
||||
{
|
||||
"classification": v.Str(
|
||||
options=[
|
||||
"autoclassified intermittent",
|
||||
"infra",
|
||||
"intermittent",
|
||||
"expected fail",
|
||||
"fixed by commit",
|
||||
"not classified",
|
||||
],
|
||||
),
|
||||
"classification_note": v.Str(),
|
||||
},
|
||||
optional=["classification_note"],
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
Contract(
|
||||
name="push_revisions",
|
||||
description="Data from the VCS about a given push.",
|
||||
validate_in=Schema(
|
||||
validate_in=v.Dict(
|
||||
{
|
||||
Required("from_date"): str,
|
||||
Required("to_date"): str,
|
||||
Required("branch"): str,
|
||||
"from_date": v.Str(),
|
||||
"to_date": v.Str(),
|
||||
"branch": v.Str(),
|
||||
}
|
||||
),
|
||||
validate_out=Schema(
|
||||
[
|
||||
validate_out=v.List(
|
||||
v.Dict(
|
||||
{
|
||||
Required("pushid"): int,
|
||||
Required("date"): int,
|
||||
Required("revs"): [str],
|
||||
"pushid": v.Int(),
|
||||
"date": v.Int(),
|
||||
"revs": v.List(v.Str()),
|
||||
}
|
||||
]
|
||||
)
|
||||
),
|
||||
),
|
||||
Contract(
|
||||
name="test_task_groups",
|
||||
description="A dict of test groups and their results for a given TestTask.",
|
||||
validate_in=Schema(
|
||||
validate_in=v.Dict(
|
||||
{
|
||||
Required("task"): TestTask,
|
||||
}
|
||||
),
|
||||
validate_out=Schema(
|
||||
{
|
||||
Marker(All(str, Length(min=1)), description="group name"): Marker(
|
||||
bool, description="group result"
|
||||
)
|
||||
"task": v.Type(TestTask),
|
||||
}
|
||||
),
|
||||
validate_out=v.Dict(extra=(v.Str(minlen=1), v.Bool())),
|
||||
),
|
||||
Contract(
|
||||
name="test_task_errors",
|
||||
description="A list of errors for a given TestTask.",
|
||||
validate_in=Schema(
|
||||
validate_in=v.Dict(
|
||||
{
|
||||
Required("task"): TestTask,
|
||||
"task": v.Type(TestTask),
|
||||
}
|
||||
),
|
||||
validate_out=Schema(
|
||||
[Marker(All(str, Length(min=1)), description="error message")]
|
||||
),
|
||||
validate_out=v.List(v.Str(minlen=1)),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -815,6 +815,14 @@ secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "cer
|
|||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
brotli = ["brotlipy (>=0.6.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "validx"
|
||||
version = "0.7"
|
||||
description = "fast, powerful, and flexible validator with sane syntax"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "virtualenv"
|
||||
version = "20.4.3"
|
||||
|
@ -834,14 +842,6 @@ six = ">=1.9.0,<2"
|
|||
docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"]
|
||||
testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)", "xonsh (>=0.9.16)"]
|
||||
|
||||
[[package]]
|
||||
name = "voluptuous"
|
||||
version = "0.12.1"
|
||||
description = ""
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "win32-setctime"
|
||||
version = "1.0.3"
|
||||
|
@ -898,7 +898,7 @@ adr = ["adr"]
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = ">=3.7,<4"
|
||||
content-hash = "c60eb461e650c7814c63fdd58592748f9b0b60862966715f0dc142f1a61b944a"
|
||||
content-hash = "71ebe5bb04d13b4d18fc0cd6fa9df66400ed29a6cb5cc4ae1fd789b2a71a9788"
|
||||
|
||||
[metadata.files]
|
||||
adr = [
|
||||
|
@ -1351,14 +1351,48 @@ urllib3 = [
|
|||
{file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"},
|
||||
{file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"},
|
||||
]
|
||||
validx = [
|
||||
{file = "ValidX-0.7-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:320984109c790d8a2568804290419cba1642307ffc9ef26f692928df7f313c47"},
|
||||
{file = "ValidX-0.7-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:402bcfa2945fb723a066c0fca7c63765880b2732c756107ec4984490d20e3203"},
|
||||
{file = "ValidX-0.7-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1ada2c7240ce85e334b86bd22f343faff13742f7eadf06f2c232c76aa9d56c48"},
|
||||
{file = "ValidX-0.7-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:8a6376a43ff4d71d450dc318f11caf7aadbd77e06a4a1fe6cdb7c8d540023fe7"},
|
||||
{file = "ValidX-0.7-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:5ef04d560706d4ea01a803c61f90b597b6703bafa45adda88b823944756cb487"},
|
||||
{file = "ValidX-0.7-cp35-cp35m-win32.whl", hash = "sha256:719587896f3a31a8774ab695433e40bfe56f2aabecdd57f738015a40ebea78a0"},
|
||||
{file = "ValidX-0.7-cp35-cp35m-win_amd64.whl", hash = "sha256:66c20bd73f0a965de86f3142b08c8231ae3cd781abf7553d20fdb7276aa1dde9"},
|
||||
{file = "ValidX-0.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a4faf64c701018fe2d7022b3fca3498ce2870c98ea2ce0844c6137c40196786"},
|
||||
{file = "ValidX-0.7-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:db1bdf1485b64da7b9581799ee6dfc3397b14457c1c744072640ad4405fcb6ee"},
|
||||
{file = "ValidX-0.7-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b06a33a2ebdaae7cfcd7294cdf150cf29c1a500838056387d68d84473192d5be"},
|
||||
{file = "ValidX-0.7-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:15e186badfa120c22c828c594c346ff8fd34876af628f7cddf6363d6a76b6f95"},
|
||||
{file = "ValidX-0.7-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e9b56e49491c9b8a2da578ebbb411aeb7bcae05cf5eda632591921738c69702f"},
|
||||
{file = "ValidX-0.7-cp36-cp36m-win32.whl", hash = "sha256:e0d944ccbb94246419faf3d12b93b8c2ec953152ec0ad01e71d8201da5230e73"},
|
||||
{file = "ValidX-0.7-cp36-cp36m-win_amd64.whl", hash = "sha256:9d3ddf6574940f7115534be7b6ce21e114a1f1fff46dff369cec779abe498d1c"},
|
||||
{file = "ValidX-0.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38322f822f941b1b5d810836c6dcf13875c4d13fb5e9d0718e6bcfce351033b9"},
|
||||
{file = "ValidX-0.7-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ab441d1621d8e26237537710d2b020a7bbe70b573c0139ce5bfc6950da15d391"},
|
||||
{file = "ValidX-0.7-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fa277c24ce52eac619e82298de929759bb23b4dbdec28ba6e9f60e40198d2509"},
|
||||
{file = "ValidX-0.7-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:152dcc598f95e2d7ed8cf6f82fb911f1fd4d2b7111a1a3a933a1116a8b44e830"},
|
||||
{file = "ValidX-0.7-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:afe1d4f1606d787a5f9a020dff6f71267feadd87e9a4a8ca5472a2d7f1edf1ac"},
|
||||
{file = "ValidX-0.7-cp37-cp37m-win32.whl", hash = "sha256:a36c3d271cdcfbeefcd921937ffa405e21025c54219687c01a5954b73d6a7e74"},
|
||||
{file = "ValidX-0.7-cp37-cp37m-win_amd64.whl", hash = "sha256:906f096360156303625b6f425414d1a4b4e9b3b72919379a95a1a9f4cd63098b"},
|
||||
{file = "ValidX-0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a9b888a9b6331f33b47071976d28fcee977c77aea2307da709417f1fb62e2202"},
|
||||
{file = "ValidX-0.7-cp38-cp38-manylinux1_i686.whl", hash = "sha256:bc63d0406041e12182451d6064f51338692bb312fd15686bf9970a5b30a3e4c7"},
|
||||
{file = "ValidX-0.7-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:95f900339a7016857813e22bd28c066e12a9dab49e0f98c22550d6dfde1dfdd1"},
|
||||
{file = "ValidX-0.7-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:f3bea80f0f8d440ba233b22e3b7153f4f08d20dcf62f209659b5b295dcb39740"},
|
||||
{file = "ValidX-0.7-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:dff33c40f90fed98ff73d50a309c3206a6e7da225e0fe0c97e9e13d5273a231d"},
|
||||
{file = "ValidX-0.7-cp38-cp38-win32.whl", hash = "sha256:8313974e13d395f59341455f08dda5bd84bf56060e033dd918bfec1156310c5d"},
|
||||
{file = "ValidX-0.7-cp38-cp38-win_amd64.whl", hash = "sha256:780bbf248223f67d5da51699c10ae348ea636706db2425ec50c20679a1f75462"},
|
||||
{file = "ValidX-0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a82987dda3a24fc44eb849a3df0661ffa7d807aa071811e0d8fc36eed0fe58ed"},
|
||||
{file = "ValidX-0.7-cp39-cp39-manylinux1_i686.whl", hash = "sha256:299b0d5eda95eb409a9771c23b1deb3c6f7499c995b6a52c3e760afd688fb3ec"},
|
||||
{file = "ValidX-0.7-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b58c861953e0785de7d02c496d2252e10841ca8e12458b37341fa5c6ebaea00d"},
|
||||
{file = "ValidX-0.7-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:1d655cbee8c5812bd92a5f83de66594cfc66bd3e0391c9f99bd11c25572d0013"},
|
||||
{file = "ValidX-0.7-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:4e086ee056a0414bbe2f06267d9c9d6c5c1a9848043b40fdf9e858ec86e3f618"},
|
||||
{file = "ValidX-0.7-cp39-cp39-win32.whl", hash = "sha256:227153f3ae19630a8ada0f6bee3d824976df8ec60e41fc56921eb6cfa9f37136"},
|
||||
{file = "ValidX-0.7-cp39-cp39-win_amd64.whl", hash = "sha256:d7783ac9ca78ccf24cfeb3606ada82ea211a79a27d12a98878529adeff09f342"},
|
||||
{file = "ValidX-0.7.tar.gz", hash = "sha256:ffbd835c3449a89c056c814205729532b9a179a4005bb99441562e2f1ab46cba"},
|
||||
]
|
||||
virtualenv = [
|
||||
{file = "virtualenv-20.4.3-py2.py3-none-any.whl", hash = "sha256:83f95875d382c7abafe06bd2a4cdd1b363e1bb77e02f155ebe8ac082a916b37c"},
|
||||
{file = "virtualenv-20.4.3.tar.gz", hash = "sha256:49ec4eb4c224c6f7dd81bb6d0a28a09ecae5894f4e593c89b0db0885f565a107"},
|
||||
]
|
||||
voluptuous = [
|
||||
{file = "voluptuous-0.12.1-py3-none-any.whl", hash = "sha256:8ace33fcf9e6b1f59406bfaf6b8ec7bcc44266a9f29080b4deb4fe6ff2492386"},
|
||||
{file = "voluptuous-0.12.1.tar.gz", hash = "sha256:663572419281ddfaf4b4197fd4942d181630120fb39b333e3adad70aeb56444b"},
|
||||
]
|
||||
win32-setctime = [
|
||||
{file = "win32_setctime-1.0.3-py3-none-any.whl", hash = "sha256:dc925662de0a6eb987f0b01f599c01a8236cb8c62831c22d9cada09ad958243e"},
|
||||
{file = "win32_setctime-1.0.3.tar.gz", hash = "sha256:4e88556c32fdf47f64165a2180ba4552f8bb32c1103a2fafd05723a0bd42bd4b"},
|
||||
|
|
|
@ -19,7 +19,6 @@ zstandard = {version = "~0", optional = true}
|
|||
python3-memcached = {version = "~1", optional = true}
|
||||
redis = {version = "~3", optional = true}
|
||||
requests = "~2"
|
||||
voluptuous = "~0"
|
||||
flake8 = "~3"
|
||||
pyyaml = "~5"
|
||||
taskcluster = ">=38"
|
||||
|
@ -27,6 +26,7 @@ lru-dict = "^1.1.7"
|
|||
|
||||
# Optional dependencies
|
||||
adr = { version = "~0", optional = true }
|
||||
ValidX = "^0.7"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pre-commit = "^2.12"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
from voluptuous import MultipleInvalid, Required, Schema
|
||||
import validx as v
|
||||
|
||||
from mozci import data
|
||||
from mozci.data.base import DataHandler, DataSource
|
||||
|
@ -16,26 +16,26 @@ FAKE_CONTRACTS = (
|
|||
Contract(
|
||||
name="foo",
|
||||
description="test",
|
||||
validate_in=Schema({Required("label"): str}),
|
||||
validate_out=Schema({Required("count"): int}),
|
||||
validate_in=v.Dict({"label": v.Str()}),
|
||||
validate_out=v.Dict({"count": v.Int()}),
|
||||
),
|
||||
Contract(
|
||||
name="bar",
|
||||
description="test",
|
||||
validate_in=Schema({Required("desc"): str}),
|
||||
validate_out=Schema({Required("amount"): int}),
|
||||
validate_in=v.Dict({"desc": v.Str()}),
|
||||
validate_out=v.Dict({"amount": v.Int()}),
|
||||
),
|
||||
Contract(
|
||||
name="baz",
|
||||
description="test",
|
||||
validate_in=Schema({Required("id"): str}),
|
||||
validate_out=Schema({Required("sum"): int}),
|
||||
validate_in=v.Dict({"id": v.Str()}),
|
||||
validate_out=v.Dict({"sum": v.Int()}),
|
||||
),
|
||||
Contract(
|
||||
name="incomplete",
|
||||
description="test",
|
||||
validate_in=Schema({}),
|
||||
validate_out=Schema({}),
|
||||
validate_in=v.Dict({}),
|
||||
validate_out=v.Dict({}),
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -67,7 +67,7 @@ def test_data_handler(monkeypatch):
|
|||
monkeypatch.setattr(DataHandler, "ALL_SOURCES", {"fake": FakeSource()})
|
||||
handler = DataHandler("fake")
|
||||
|
||||
with pytest.raises(MultipleInvalid):
|
||||
with pytest.raises(v.exc.SchemaError):
|
||||
handler.get("baz")
|
||||
|
||||
with pytest.raises(SourcesNotFound):
|
||||
|
@ -79,10 +79,10 @@ def test_data_handler(monkeypatch):
|
|||
with pytest.raises(ContractNotFound):
|
||||
handler.get("fleem")
|
||||
|
||||
with pytest.raises(MultipleInvalid):
|
||||
with pytest.raises(v.exc.SchemaError):
|
||||
handler.get("foo")
|
||||
|
||||
with pytest.raises(MultipleInvalid):
|
||||
with pytest.raises(v.exc.SchemaError):
|
||||
handler.get("foo", label="foo")
|
||||
|
||||
assert handler.get("bar", desc="tada") == {"amount": 1}
|
||||
|
|
Загрузка…
Ссылка в новой задаче