Skip to content

Commit 7d88773

Browse files
committed
feat: add dict-style to python attributes
1 parent e90f8d8 commit 7d88773

File tree

2 files changed

+69
-7
lines changed

2 files changed

+69
-7
lines changed

mlir/lib/Bindings/Python/IRCore.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2730,14 +2730,59 @@ class PyOpAttributeMap {
27302730
operation->get(), toMlirStringRef(name)));
27312731
}
27322732

2733+
template <typename F>
2734+
auto forEachAttr(F fn) {
2735+
intptr_t n = mlirOperationGetNumAttributes(operation->get());
2736+
for (intptr_t i = 0; i < n; ++i) {
2737+
MlirNamedAttribute na = mlirOperationGetAttribute(operation->get(), i);
2738+
MlirStringRef name = mlirIdentifierStr(na.name);
2739+
fn(name, na.attribute);
2740+
}
2741+
}
2742+
27332743
static void bind(nb::module_ &m) {
27342744
nb::class_<PyOpAttributeMap>(m, "OpAttributeMap")
27352745
.def("__contains__", &PyOpAttributeMap::dunderContains)
27362746
.def("__len__", &PyOpAttributeMap::dunderLen)
27372747
.def("__getitem__", &PyOpAttributeMap::dunderGetItemNamed)
27382748
.def("__getitem__", &PyOpAttributeMap::dunderGetItemIndexed)
27392749
.def("__setitem__", &PyOpAttributeMap::dunderSetItem)
2740-
.def("__delitem__", &PyOpAttributeMap::dunderDelItem);
2750+
.def("__delitem__", &PyOpAttributeMap::dunderDelItem)
2751+
.def("__iter__",
2752+
[](PyOpAttributeMap &self) {
2753+
nb::list keys;
2754+
self.forEachAttr([&](MlirStringRef name, MlirAttribute) {
2755+
keys.append(nb::str(name.data, name.length));
2756+
});
2757+
return nb::iter(keys);
2758+
})
2759+
.def("keys",
2760+
[](PyOpAttributeMap &self) {
2761+
nb::list out;
2762+
self.forEachAttr([&](MlirStringRef name, MlirAttribute) {
2763+
out.append(nb::str(name.data, name.length));
2764+
});
2765+
return out;
2766+
})
2767+
.def("values",
2768+
[](PyOpAttributeMap &self) {
2769+
nb::list out;
2770+
self.forEachAttr([&](MlirStringRef, MlirAttribute attr) {
2771+
out.append(PyAttribute(self.operation->getContext(), attr)
2772+
.maybeDownCast());
2773+
});
2774+
return out;
2775+
})
2776+
.def("items", [](PyOpAttributeMap &self) {
2777+
nb::list out;
2778+
self.forEachAttr([&](MlirStringRef name, MlirAttribute attr) {
2779+
out.append(
2780+
nb::make_tuple(nb::str(name.data, name.length),
2781+
PyAttribute(self.operation->getContext(), attr)
2782+
.maybeDownCast()));
2783+
});
2784+
return out;
2785+
});
27412786
}
27422787

27432788
private:

mlir/test/python/ir/operation.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -569,14 +569,31 @@ def testOperationAttributes():
569569
# CHECK: Attribute value b'text'
570570
print(f"Attribute value {sattr.value_bytes}")
571571

572+
# Python dict-style iteration
572573
# We don't know in which order the attributes are stored.
573-
# CHECK-DAG: NamedAttribute(dependent="text")
574-
# CHECK-DAG: NamedAttribute(other.attribute=3.000000e+00 : f64)
575-
# CHECK-DAG: NamedAttribute(some.attribute=1 : i8)
576-
for attr in op.attributes:
577-
print(str(attr))
574+
# CHECK-DAG: dependent
575+
# CHECK-DAG: other.attribute
576+
# CHECK-DAG: some.attribute
577+
for name in op.attributes:
578+
print(name)
579+
580+
# Basic dict-like introspection
581+
# CHECK: True
582+
print("some.attribute" in op.attributes)
583+
# CHECK: False
584+
print("missing" in op.attributes)
585+
# CHECK: Keys: ['dependent', 'other.attribute', 'some.attribute']
586+
print("Keys:", sorted(op.attributes.keys()))
587+
# CHECK: Values count 3
588+
print("Values count", len(op.attributes.values()))
589+
# CHECK: Items count 3
590+
print("Items count", len(op.attributes.items()))
591+
592+
# Dict() conversion test
593+
d = {k: v.value for k, v in dict(op.attributes).items()}
594+
# CHECK: Dict mapping {'dependent': 'text', 'other.attribute': 3.0, 'some.attribute': 1}
595+
print("Dict mapping", d)
578596

579-
# Check that exceptions are raised as expected.
580597
try:
581598
op.attributes["does_not_exist"]
582599
except KeyError:

0 commit comments

Comments
 (0)