mirror of
https://github.com/p2p-ld/numpydantic.git
synced 2024-09-19 23:44:28 +00:00
121 lines
3.9 KiB
Python
121 lines
3.9 KiB
Python
|
"""
|
||
|
Test custom features of the pydantic generator
|
||
|
|
||
|
Note that since this is largely a subclass, we don't test all of the functionality of the generator
|
||
|
because it's tested in the base linkml package.
|
||
|
"""
|
||
|
import re
|
||
|
import sys
|
||
|
import typing
|
||
|
|
||
|
import numpy as np
|
||
|
import pytest
|
||
|
from pydantic import BaseModel
|
||
|
|
||
|
|
||
|
def test_arraylike(imported_schema):
|
||
|
"""
|
||
|
Arraylike classes are converted to slots that specify nptyping arrays
|
||
|
|
||
|
array: Optional[Union[
|
||
|
NDArray[Shape["* x, * y"], Number],
|
||
|
NDArray[Shape["* x, * y, 3 z"], Number],
|
||
|
NDArray[Shape["* x, * y, 3 z, 4 a"], Number]
|
||
|
]] = Field(None)
|
||
|
"""
|
||
|
# check that we have gotten an NDArray annotation and its shape is correct
|
||
|
array = imported_schema["core"].MainTopLevel.model_fields["array"].annotation
|
||
|
args = typing.get_args(array)
|
||
|
for i, shape in enumerate(("* x, * y", "* x, * y, 3 z", "* x, * y, 3 z, 4 a")):
|
||
|
assert isinstance(args[i], NDArrayMeta)
|
||
|
assert args[i].__args__[0].__args__
|
||
|
assert args[i].__args__[1] == np.number
|
||
|
|
||
|
# we shouldn't have an actual class for the array
|
||
|
assert not hasattr(imported_schema["core"], "MainTopLevel__Array")
|
||
|
assert not hasattr(imported_schema["core"], "MainTopLevelArray")
|
||
|
|
||
|
|
||
|
def test_inject_fields(imported_schema):
|
||
|
"""
|
||
|
Our root model should have the special fields we injected
|
||
|
"""
|
||
|
base = imported_schema["core"].ConfiguredBaseModel
|
||
|
assert "hdf5_path" in base.model_fields
|
||
|
assert "object_id" in base.model_fields
|
||
|
|
||
|
|
||
|
def test_linkml_meta(imported_schema):
|
||
|
"""
|
||
|
We should be able to store some linkml metadata with our classes
|
||
|
"""
|
||
|
meta = imported_schema["core"].LinkML_Meta
|
||
|
assert "tree_root" in meta.model_fields
|
||
|
assert imported_schema["core"].MainTopLevel.linkml_meta.default.tree_root == True
|
||
|
assert imported_schema["core"].OtherClass.linkml_meta.default.tree_root == False
|
||
|
|
||
|
|
||
|
def test_skip(linkml_schema):
|
||
|
"""
|
||
|
We can skip slots and classes
|
||
|
"""
|
||
|
modules = generate_and_import(
|
||
|
linkml_schema,
|
||
|
split=False,
|
||
|
generator_kwargs={
|
||
|
"SKIP_SLOTS": ("SkippableSlot",),
|
||
|
"SKIP_CLASSES": ("Skippable", "skippable"),
|
||
|
},
|
||
|
)
|
||
|
assert not hasattr(modules["core"], "Skippable")
|
||
|
assert "SkippableSlot" not in modules["core"].MainTopLevel.model_fields
|
||
|
|
||
|
|
||
|
def test_inline_with_identifier(imported_schema):
|
||
|
"""
|
||
|
By default, if a class has an identifier attribute, it is inlined
|
||
|
as a string rather than its class. We overrode that to be able to make dictionaries of collections
|
||
|
"""
|
||
|
main = imported_schema["core"].MainTopLevel
|
||
|
inline = main.model_fields["inline_dict"].annotation
|
||
|
assert typing.get_origin(typing.get_args(inline)[0]) == dict
|
||
|
# god i hate pythons typing interface
|
||
|
otherclass, stillanother = typing.get_args(
|
||
|
typing.get_args(typing.get_args(inline)[0])[1]
|
||
|
)
|
||
|
assert otherclass is imported_schema["core"].OtherClass
|
||
|
assert stillanother is imported_schema["core"].StillAnotherClass
|
||
|
|
||
|
|
||
|
def test_namespace(imported_schema):
|
||
|
"""
|
||
|
Namespace schema import all classes from the other schema
|
||
|
Returns:
|
||
|
|
||
|
"""
|
||
|
ns = imported_schema["namespace"]
|
||
|
|
||
|
for classname, modname in (
|
||
|
("MainThing", "test_schema.imported"),
|
||
|
("Arraylike", "test_schema.imported"),
|
||
|
("MainTopLevel", "test_schema.core"),
|
||
|
("Skippable", "test_schema.core"),
|
||
|
("OtherClass", "test_schema.core"),
|
||
|
("StillAnotherClass", "test_schema.core"),
|
||
|
):
|
||
|
assert hasattr(ns, classname)
|
||
|
if imported_schema["split"]:
|
||
|
assert getattr(ns, classname).__module__ == modname
|
||
|
|
||
|
|
||
|
def test_get_set_item(imported_schema):
|
||
|
"""We can get and set without explicitly addressing array"""
|
||
|
cls = imported_schema["core"].MainTopLevel(array=np.array([[1, 2, 3], [4, 5, 6]]))
|
||
|
cls[0] = 50
|
||
|
assert (cls[0] == 50).all()
|
||
|
assert (cls.array[0] == 50).all()
|
||
|
|
||
|
cls[1, 1] = 100
|
||
|
assert cls[1, 1] == 100
|
||
|
assert cls.array[1, 1] == 100
|