1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
import ast
import inspect
from typing import ForwardRef
from sphinx_needs.data import NeedsCoreFields, NeedsInfoType
def test_consistent():
"""
Ideally NeedsCoreFields and NeedsInfoType would be merged, so there is no duplication,
but I'm not sure this is possible (to encode both the static and dynamic data required).
So at least here, we check that they are consistent with each other.
"""
# check fields are consistent
assert set(NeedsCoreFields).issubset(set(NeedsInfoType.__annotations__))
# check field types are consistent with schema
for field, data in NeedsCoreFields.items():
if not (schema := data.get("schema")):
continue
type_ = NeedsInfoType.__annotations__[field]
assert isinstance(type_, ForwardRef)
type_str = type_.__forward_arg__
if type_str.startswith("Required"):
type_str = type_str[9:-1]
if type_str == "str" or type_str == "str | Text":
assert schema["type"] == "string", field
elif type_str == "int":
assert schema["type"] == "integer", field
elif type_str == "bool":
assert schema["type"] == "boolean", field
elif type_str in ("str | None", "None | str"):
assert schema["type"] == ["string", "null"], field
elif type_str in ("int | None", "None | int"):
assert schema["type"] == ["integer", "null"], field
elif type_str in ("bool | None", "None | bool"):
assert schema["type"] == ["boolean", "null"], field
elif type_str == "list[str]":
assert schema["type"] == "array", field
assert schema["items"]["type"] == "string", field
elif type_str == "dict[str, str]":
assert schema["type"] == "object", field
assert schema["additionalProperties"]["type"] == "string", field
elif type_str.startswith("dict["):
assert schema["type"] == "object", field
else:
raise ValueError(f"Unknown type: {type_str!r} for {field!r}")
# check descriptions are consistent
source = inspect.getsource(NeedsInfoType)
klass = ast.parse(source).body[0]
descriptions = {}
for i, node in enumerate(klass.body):
if (
isinstance(node, ast.AnnAssign)
and len(klass.body) > i + 1
and isinstance(klass.body[i + 1], ast.Expr)
):
desc = " ".join(
[li.strip() for li in klass.body[i + 1].value.value.splitlines()]
)
descriptions[node.target.id] = desc.strip()
for field, desc in descriptions.items():
if field in NeedsCoreFields:
assert NeedsCoreFields[field]["description"] == desc, field
|