lib.wiring: in is_compliant(sig, obj)
, check that obj
is an interface object with that signature.
Fixes #935.
This commit is contained in:
parent
8b48af6de8
commit
04f906965a
|
@ -405,6 +405,21 @@ class Signature(metaclass=SignatureMeta):
|
||||||
yield from iter_dimensions(value, dimensions=member.dimensions, path=path)
|
yield from iter_dimensions(value, dimensions=member.dimensions, path=path)
|
||||||
|
|
||||||
def is_compliant(self, obj, *, reasons=None, path=("obj",)):
|
def is_compliant(self, obj, *, reasons=None, path=("obj",)):
|
||||||
|
if not hasattr(obj, "signature"):
|
||||||
|
if reasons is not None:
|
||||||
|
reasons.append(f"{_format_path(path)} does not have an attribute 'signature'")
|
||||||
|
return False
|
||||||
|
if not isinstance(obj.signature, Signature):
|
||||||
|
if reasons is not None:
|
||||||
|
reasons.append(f"{_format_path(path + ('signature',))} is expected to be "
|
||||||
|
f"a signature, but it is a {obj.signature!r}")
|
||||||
|
return False
|
||||||
|
if self != obj.signature:
|
||||||
|
if reasons is not None:
|
||||||
|
reasons.append(f"{_format_path(path + ('signature',))} is expected to be equal "
|
||||||
|
f"to this signature, {self!r}, but it is a {obj.signature!r}")
|
||||||
|
return False
|
||||||
|
|
||||||
def check_attr_value(member, attr_value, *, path):
|
def check_attr_value(member, attr_value, *, path):
|
||||||
if member.is_port:
|
if member.is_port:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -416,7 +416,32 @@ class SignatureTestCase(unittest.TestCase):
|
||||||
(("d", "s"), In (1), intf.d.s),
|
(("d", "s"), In (1), intf.d.s),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_is_compliant_signature(self):
|
||||||
|
sig = Signature({})
|
||||||
|
|
||||||
|
obj1 = NS()
|
||||||
|
self.assertFalse(sig.is_compliant(obj1))
|
||||||
|
reasons = []
|
||||||
|
self.assertFalse(sig.is_compliant(obj1, reasons=reasons))
|
||||||
|
self.assertEqual(reasons, ["'obj' does not have an attribute 'signature'"])
|
||||||
|
|
||||||
|
obj = NS(signature=1)
|
||||||
|
self.assertFalse(sig.is_compliant(obj))
|
||||||
|
reasons = []
|
||||||
|
self.assertFalse(sig.is_compliant(obj, reasons=reasons))
|
||||||
|
self.assertEqual(reasons, ["'obj.signature' is expected to be a signature, but it is a 1"])
|
||||||
|
|
||||||
|
obj = NS(signature=Signature({"a": In(1)}))
|
||||||
|
self.assertFalse(sig.is_compliant(obj))
|
||||||
|
reasons = []
|
||||||
|
self.assertFalse(sig.is_compliant(obj, reasons=reasons))
|
||||||
|
self.assertEqual(reasons, [
|
||||||
|
"'obj.signature' is expected to be equal to this signature, "
|
||||||
|
"Signature({}), but it is a Signature({'a': In(1)})"
|
||||||
|
])
|
||||||
|
|
||||||
def assertNotCompliant(self, reason_regex, sig, obj):
|
def assertNotCompliant(self, reason_regex, sig, obj):
|
||||||
|
obj.signature = sig
|
||||||
self.assertFalse(sig.is_compliant(obj))
|
self.assertFalse(sig.is_compliant(obj))
|
||||||
reasons = []
|
reasons = []
|
||||||
self.assertFalse(sig.is_compliant(obj, reasons=reasons))
|
self.assertFalse(sig.is_compliant(obj, reasons=reasons))
|
||||||
|
@ -474,25 +499,32 @@ class SignatureTestCase(unittest.TestCase):
|
||||||
self.assertNotCompliant(
|
self.assertNotCompliant(
|
||||||
r"^'obj\.a' does not have an attribute 'b'$",
|
r"^'obj\.a' does not have an attribute 'b'$",
|
||||||
sig=Signature({"a": Out(Signature({"b": In(1)}))}),
|
sig=Signature({"a": Out(Signature({"b": In(1)}))}),
|
||||||
obj=NS(a=Signal()))
|
obj=NS(a=NS(signature=Signature({"b": In(1)}))))
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
Signature({"a": In(1)}).is_compliant(
|
Signature({"a": In(1)}).is_compliant(
|
||||||
NS(a=Signal())))
|
NS(signature=Signature({"a": In(1)}),
|
||||||
|
a=Signal())))
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
Signature({"a": In(1)}).is_compliant(
|
Signature({"a": In(1)}).is_compliant(
|
||||||
NS(a=Const(1))))
|
NS(signature=Signature({"a": In(1)}),
|
||||||
|
a=Const(1))))
|
||||||
self.assertTrue( # list
|
self.assertTrue( # list
|
||||||
Signature({"a": In(1).array(2, 2)}).is_compliant(
|
Signature({"a": In(1).array(2, 2)}).is_compliant(
|
||||||
NS(a=[[Const(1), Const(1)], [Signal(), Signal()]])))
|
NS(signature=Signature({"a": In(1).array(2, 2)}),
|
||||||
|
a=[[Const(1), Const(1)], [Signal(), Signal()]])))
|
||||||
self.assertTrue( # tuple
|
self.assertTrue( # tuple
|
||||||
Signature({"a": In(1).array(2, 2)}).is_compliant(
|
Signature({"a": In(1).array(2, 2)}).is_compliant(
|
||||||
NS(a=((Const(1), Const(1)), (Signal(), Signal())))))
|
NS(signature=Signature({"a": In(1).array(2, 2)}),
|
||||||
|
a=((Const(1), Const(1)), (Signal(), Signal())))))
|
||||||
self.assertTrue( # mixed list and tuple
|
self.assertTrue( # mixed list and tuple
|
||||||
Signature({"a": In(1).array(2, 2)}).is_compliant(
|
Signature({"a": In(1).array(2, 2)}).is_compliant(
|
||||||
NS(a=[[Const(1), Const(1)], (Signal(), Signal())])))
|
NS(signature=Signature({"a": In(1).array(2, 2)}),
|
||||||
|
a=[[Const(1), Const(1)], (Signal(), Signal())])))
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
Signature({"a": Out(Signature({"b": In(1)}))}).is_compliant(
|
Signature({"a": Out(Signature({"b": In(1)}))}).is_compliant(
|
||||||
NS(a=NS(b=Signal()))))
|
NS(signature=Signature({"a": Out(Signature({"b": In(1)}))}),
|
||||||
|
a=NS(signature=Signature({"b": In(1)}),
|
||||||
|
b=Signal()))))
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
sig = Signature({"a": In(1)})
|
sig = Signature({"a": In(1)})
|
||||||
|
@ -933,9 +965,9 @@ class ConnectTestCase(unittest.TestCase):
|
||||||
m = Module()
|
m = Module()
|
||||||
connect(m,
|
connect(m,
|
||||||
p=NS(signature=Signature({"a": Out(Signature({"f": Out(1)}))}),
|
p=NS(signature=Signature({"a": Out(Signature({"f": Out(1)}))}),
|
||||||
a=NS(f=Signal(name='p__a'))),
|
a=NS(signature=Signature({"f": Out(1)}), f=Signal(name='p__a'))),
|
||||||
q=NS(signature=Signature({"a": In(Signature({"f": Out(1)}))}),
|
q=NS(signature=Signature({"a": In(Signature({"f": Out(1)}))}),
|
||||||
a=NS(f=Signal(name='q__a'))))
|
a=NS(signature=Signature({"f": Out(1)}).flip(), f=Signal(name='q__a'))))
|
||||||
self.assertEqual([repr(stmt) for stmt in m._statements], [
|
self.assertEqual([repr(stmt) for stmt in m._statements], [
|
||||||
'(eq (sig q__a) (sig p__a))'
|
'(eq (sig q__a) (sig p__a))'
|
||||||
])
|
])
|
||||||
|
|
Loading…
Reference in a new issue