From f605e513e0f54a6ab0efabaefdd578a980af7b05 Mon Sep 17 00:00:00 2001 From: beam Date: Fri, 23 Oct 2026 00:55:57 +0000 Subject: [PATCH] beam: fix _key mixed-tuple crash in toposort modules (sortable wrapper) --- wizard-work/beam/toposort.py | 30 +++++++++++++++++++------- wizard-work/beam/toposort/toposort.py | 31 +++++++++++++++++++-------- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/wizard-work/beam/toposort.py b/wizard-work/beam/toposort.py index d377185..de77f22 100644 --- a/wizard-work/beam/toposort.py +++ b/wizard-work/beam/toposort.py @@ -169,12 +169,26 @@ def topo_sort(graph: Mapping[Any, Iterable[Any]]) -> TopoResult: return TopoResult(sorted=None, cycle=cycle) +class _Sortable: + __slots__ = ("x", "tn") + def __init__(self, x): + self.x = x + self.tn = type(x).__name__ + def __lt__(self, other): + if not isinstance(other, _Sortable): + return NotImplemented + if self.tn != other.tn: + return self.tn < other.tn + try: + return self.x < other.x + except Exception: + rx, ry = repr(self.x), repr(other.x) + if rx != ry: + return rx < ry + return id(self.x) < id(other.x) + def __eq__(self, other): + return isinstance(other, _Sortable) and self.x == other.x + + def _key(x): - tn = type(x).__name__ - if isinstance(x, (set, frozenset)): - return (1, tn, repr(x), id(x)) - try: - _ = x < x - except Exception: - return (1, tn, repr(x), id(x)) - return (0, tn, x) \ No newline at end of file + return _Sortable(x) \ No newline at end of file diff --git a/wizard-work/beam/toposort/toposort.py b/wizard-work/beam/toposort/toposort.py index 22ab30a..de77f22 100644 --- a/wizard-work/beam/toposort/toposort.py +++ b/wizard-work/beam/toposort/toposort.py @@ -169,13 +169,26 @@ def topo_sort(graph: Mapping[Any, Iterable[Any]]) -> TopoResult: return TopoResult(sorted=None, cycle=cycle) +class _Sortable: + __slots__ = ("x", "tn") + def __init__(self, x): + self.x = x + self.tn = type(x).__name__ + def __lt__(self, other): + if not isinstance(other, _Sortable): + return NotImplemented + if self.tn != other.tn: + return self.tn < other.tn + try: + return self.x < other.x + except Exception: + rx, ry = repr(self.x), repr(other.x) + if rx != ry: + return rx < ry + return id(self.x) < id(other.x) + def __eq__(self, other): + return isinstance(other, _Sortable) and self.x == other.x + + def _key(x): - tn = type(x).__name__ - # Probe whether instances of this type support ordering; if not, fall back - # to a repr/id-based key so mixed or unorderable node types never crash - # the ready-queue sort or cycle reconstruction. - try: - _ = x < x - except (TypeError, Exception): - return (1, tn, repr(x), id(x)) - return (0, tn, x) \ No newline at end of file + return _Sortable(x) \ No newline at end of file