Skip to content

Conversation

@makslevental
Copy link
Contributor

@makslevental makslevental commented Dec 3, 2025

Generates type stubs like

class RegionSequence(Sequence[Region]):
    def __add__(self, arg: RegionSequence, /) -> list[Region]: ...

    def __iter__(self) -> RegionIterator:
        """Returns an iterator over the regions in the sequence."""

@makslevental
Copy link
Contributor Author

@ingomueller-net can you try this and see if it fixes you?

@makslevental makslevental force-pushed the users/makslevental/sliceabletypehint branch from e2291a9 to d865b48 Compare December 3, 2025 20:26
@ingomueller-net
Copy link
Contributor

@ingomueller-net can you try this and see if it fixes you?

Yes, it does! So nice! I knew you'd come up with something 😉

@makslevental makslevental force-pushed the users/makslevental/sliceabletypehint branch from d865b48 to 3b2ab0c Compare December 4, 2025 22:00
@makslevental makslevental marked this pull request as ready for review December 4, 2025 22:00
@llvmbot llvmbot added the mlir label Dec 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 4, 2025

@llvm/pr-subscribers-mlir

Author: Maksim Levental (makslevental)

Changes

Generates type stubs like

class RegionSequence(Sequence[Region]):
    def __add__(self, arg: RegionSequence, /) -> list[Region]: ...

    def __iter__(self) -> RegionIterator:
        """Returns an iterator over the regions in the sequence."""

WIP (will polish up if it works for us)


Full diff: https://github.com/llvm/llvm-project/pull/170551.diff

2 Files Affected:

  • (modified) mlir/lib/Bindings/Python/NanobindUtils.h (+12-1)
  • (modified) mlir/test/python/ir/operation.py (+4)
diff --git a/mlir/lib/Bindings/Python/NanobindUtils.h b/mlir/lib/Bindings/Python/NanobindUtils.h
index 658e8ad5330ef..4a78ec96346a2 100644
--- a/mlir/lib/Bindings/Python/NanobindUtils.h
+++ b/mlir/lib/Bindings/Python/NanobindUtils.h
@@ -16,9 +16,11 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/DataTypes.h"
+#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/raw_ostream.h"
 
 #include <string>
+#include <typeinfo>
 #include <variant>
 
 template <>
@@ -344,7 +346,16 @@ class Sliceable {
 
   /// Binds the indexing and length methods in the Python class.
   static void bind(nanobind::module_ &m) {
-    auto clazz = nanobind::class_<Derived>(m, Derived::pyClassName)
+    const std::type_info &elemTy = typeid(ElementTy);
+    PyObject *elemTyInfo = nanobind::detail::nb_type_lookup(&elemTy);
+    assert(elemTyInfo &&
+           "expected nb_type_lookup to succeed for Sliceable elemTy");
+    nanobind::handle elemTyName = nanobind::detail::nb_type_name(elemTyInfo);
+    std::string sig = std::string("class ") + Derived::pyClassName +
+                      "(collections.abc.Sequence[" +
+                      nanobind::cast<std::string>(elemTyName) + "])";
+    auto clazz = nanobind::class_<Derived>(m, Derived::pyClassName,
+                                           nanobind::sig(sig.c_str()))
                      .def("__add__", &Sliceable::dunderAdd);
     Derived::bindDerived(clazz);
 
diff --git a/mlir/test/python/ir/operation.py b/mlir/test/python/ir/operation.py
index ca99c2a985242..d124c284197b8 100644
--- a/mlir/test/python/ir/operation.py
+++ b/mlir/test/python/ir/operation.py
@@ -43,6 +43,10 @@ def testTraverseOpRegionBlockIterators():
     )
     op = module.operation
     assert op.context is ctx
+    # Note, __nb_signature__ stores the fully-qualified signature - the actual type stub emitted is
+    # class RegionSequence(Sequence[Region])
+    # CHECK: class RegionSequence(collections.abc.Sequence[mlir._mlir_libs._mlir.ir.Region])
+    print(RegionSequence.__nb_signature__)
     # Get the block using iterators off of the named collections.
     regions = list(op.regions[:])
     blocks = list(regions[0].blocks)

@makslevental makslevental force-pushed the users/makslevental/sliceabletypehint branch from 3b2ab0c to 7b233f7 Compare December 4, 2025 22:01
Comment on lines +351 to +352
assert(elemTyInfo &&
"expected nb_type_lookup to succeed for Sliceable elemTy");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no way for this to fail - the ElementTy needs to be registered before Sliceable[ElementTy] can be registered...

nanobind::handle elemTyName = nanobind::detail::nb_type_name(elemTyInfo);
std::string sig = std::string("class ") + Derived::pyClassName +
"(collections.abc.Sequence[" +
nanobind::cast<std::string>(elemTyName) + "])";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have ElementTy::pyClassName similarly to Derived::pyClassName? Maybe not everywhere, but something to consider. This is probably the first time I see typeid being used in non-toy code so I don't know how well it works across platforms.

Copy link
Contributor Author

@makslevental makslevental Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have ElementTy::pyClassName similarly to Derived::pyClassName?

No:

This is probably the first time I see typeid being used in non-toy code so I don't know how well it works across platforms.

You realize that all of nanobind/pybind hinges on typeid right?

https://github.com/search?q=repo%3Awjakob%2Fnanobind%20typeid&type=code

Specifically the core impl (the cpp to python mapping) uses std::type_info

https://github.com/wjakob/nanobind/blob/892dd8173dd6fad4ec3a50eaa51863ae45c3205d/src/nb_internals.h#L381

https://github.com/wjakob/nanobind/blob/892dd8173dd6fad4ec3a50eaa51863ae45c3205d/include/nanobind/nb_class.h#L564

Ie that's why RTTI is on for the bindings. So we can be sure it works in all the places the bindings work 🙂.

Copy link
Contributor

@ingomueller-net ingomueller-net left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but I am not precluding @ftynse's comments...

# Note, __nb_signature__ stores the fully-qualified signature - the actual type stub emitted is
# class RegionSequence(Sequence[Region])
# CHECK: class RegionSequence(collections.abc.Sequence[mlir._mlir_libs._mlir.ir.Region])
print(RegionSequence.__nb_signature__)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's a nice way to test this!

@makslevental makslevental merged commit e6d1dea into main Dec 5, 2025
10 checks passed
@makslevental makslevental deleted the users/makslevental/sliceabletypehint branch December 5, 2025 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants