diff --git a/src/errors.cpp b/src/errors.cpp
index 5112debf..cfe1a70f 100644
--- a/src/errors.cpp
+++ b/src/errors.cpp
@@ -16,6 +16,8 @@
// along with this program. If not, see .
//
+#include "errors.hpp"
+
#include
#include
diff --git a/src/errors.hpp b/src/errors.hpp
new file mode 100644
index 00000000..01ae7261
--- /dev/null
+++ b/src/errors.hpp
@@ -0,0 +1,29 @@
+//
+// libsemigroups_pybind11
+// Copyright (C) 2026 James D. Mitchell
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+#ifndef SRC_ERRORS_HPP_
+#define SRC_ERRORS_HPP_
+
+#include
+#include
+
+namespace libsemigroups {
+
+ std::string formatted_error_message(std::runtime_error const& e);
+}
+#endif // SRC_ERRORS_HPP_
diff --git a/src/transf.cpp b/src/transf.cpp
index 71b47a15..69920a0f 100644
--- a/src/transf.cpp
+++ b/src/transf.cpp
@@ -16,6 +16,8 @@
// along with this program. If not, see .
//
+#include
+
// libsemigroups headers
#include
#include
@@ -27,7 +29,8 @@
// libsemigroups_pybind11....
#include "debug.hpp"
-#include "main.hpp" // for init_transf
+#include "errors.hpp" // for formatted_error_message
+#include "main.hpp" // for init_transf
namespace libsemigroups {
@@ -104,16 +107,27 @@ the image of the point ``i`` under the {0} is ``imgs[i]``.
"__getitem__",
[](PTransfSubclass const& a,
size_t b) -> int_or_unsigned_constant {
- auto result = a.at(b);
- if (result != UNDEFINED) {
- return {result};
+ // __getitem__ is expected by python to throw an IndexError which
+ // corresponds to a std::out_of_range for things like list(a) to
+ // work.
+ try {
+ auto result = a.at(b);
+ if (result != UNDEFINED) {
+ return {result};
+ }
+ return {UNDEFINED};
+ } catch (LibsemigroupsException const& e) {
+ throw std::out_of_range(formatted_error_message(e));
}
- return {UNDEFINED};
},
py::is_operator());
thing.def("__hash__", &PTransfSubclass::hash_value, py::is_operator());
+ thing.def("__iter__", [](PTransfSubclass const& self) {
+ return py::make_iterator(self.begin(), self.end());
+ });
+
////////////////////////////////////////////////////////////////////////
// Non-special methods
////////////////////////////////////////////////////////////////////////
@@ -179,6 +193,7 @@ yielding these values.
doc_type_name,
long_name)
.c_str());
+
thing.def(
"increase_degree_by",
[](PTransfSubclass& self, size_t m) -> PTransfSubclass& {
@@ -718,7 +733,7 @@ fewer points requiring less space per point.
m.def("transf_inverse",
py::overload_cast(&inverse));
} // bind_perm
- } // namespace
+ } // namespace
void init_transf(py::module& m) {
// Transformations
diff --git a/tests/test_stephen.py b/tests/test_stephen.py
index b5305018..f9be2e32 100644
--- a/tests/test_stephen.py
+++ b/tests/test_stephen.py
@@ -68,7 +68,7 @@ def check_000(s):
]
-# The following is needed to that we can sort lists with a custom order.
+# The following is needed so that we can sort lists with a custom order.
# Why does Python not support a comparator directly? Who knows.
# Why does it not automatically convert a boolean comparator to a key function? WHO KNOWS!
def lexicographic_compare_comparator(x, y) -> int: