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: