class Attrs(OrderedDict):
def __init__(self, **attrs):
for attr_key, attr_value in attrs.items():
- if not isinstance(attr_value, str):
- raise TypeError("Attribute value must be a string, not {!r}"
+ if not (attr_value is None or isinstance(attr_value, str)):
+ raise TypeError("Attribute value must be None or str, not {!r}"
.format(attr_value))
super().__init__(**attrs)
def __repr__(self):
- return "(attrs {})".format(" ".join("{}={}".format(k, v)
- for k, v in self.items()))
+ items = []
+ for key, value in self.items():
+ if value is None:
+ items.append("!" + key)
+ else:
+ items.append(key + "=" + value)
+ return "(attrs {})".format(" ".join(items))
class Clock:
if isinstance(resource.ios[0], Subsignal):
fields = OrderedDict()
for sub in resource.ios:
+ sub_attrs = {k: v for k, v in {**attrs, **sub.attrs}.items() if v is not None}
fields[sub.name] = resolve(sub, dir[sub.name], xdr[sub.name],
name="{}__{}".format(name, sub.name),
- attrs={**attrs, **sub.attrs})
+ attrs=sub_attrs)
return Record([
(f_name, f.layout) for (f_name, f) in fields.items()
], fields=fields, name=name)
self.assertEqual(a["IO_STANDARD"], "LVCMOS33")
self.assertEqual(repr(a), "(attrs IO_STANDARD=LVCMOS33 PULLUP=1)")
+ def test_remove(self):
+ a = Attrs(FOO=None)
+ self.assertEqual(a["FOO"], None)
+ self.assertEqual(repr(a), "(attrs !FOO)")
+
def test_wrong_value(self):
with self.assertRaises(TypeError,
- msg="Attribute value must be a string, not 1"):
+ msg="Attribute value must be None or str, not 1"):
a = Attrs(FOO=1)