Skip to content

ConcurrentExecutorListResults: sorted() on results may compare ExecutionResult namedtuples unnecessarily #715

@dkropachev

Description

@dkropachev

In ConcurrentExecutorListResults._results() (cassandra/concurrent.py:207), results are sorted using:

return [r[1] for r in sorted(self._results_queue)]

self._results_queue contains (idx, ExecutionResult(success, result_or_exc)) tuples. Since sorted() compares full tuples, Python may fall through to comparing ExecutionResult namedtuples when indices are equal. In practice indices are unique so this doesn't trigger today, but if it ever did, comparing heterogeneous result_or_exc values (exceptions, result sets, dicts, etc.) raises TypeError:

>>> from cassandra.concurrent import ExecutionResult
>>> results_queue = [
...     (0, ExecutionResult(False, TypeError('type error'))),
...     (0, ExecutionResult(False, ValueError('value error'))),
... ]
>>> sorted(results_queue)
TypeError: '<' not supported between instances of 'ValueError' and 'TypeError'
>>> results_queue = [
...     (0, ExecutionResult(True, [[1,2,3]])),
...     (0, ExecutionResult(True, {'a': 1})),
... ]
>>> sorted(results_queue)
TypeError: '<' not supported between instances of 'dict' and 'list'

Additionally, sorting by the full tuple is wasteful — comparing ExecutionResult objects is unnecessary work even when it succeeds.

The fix is to use an explicit sort key:

return [r[1] for r in sorted(self._results_queue, key=lambda x: x[0])]

This is clearer about intent (sort by insertion index), avoids unnecessary comparisons, and is defensive against any future code path that might produce duplicate indices.

Spotted in the wild

https://github.com/scylladb/python-driver/actions/runs/22284500171/job/64460379139

logs_58180451190.zip

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions