Whole file
patrick-kidger/tinyio
The author described this change as “Yielding already-started (but not yet completed, and not yet seen by the loop) generators will now correctly raise an error.”. It counts as a record because the checks below fail on the code as it stood at e43ae6123 and pass on 199c5a01c, with nothing else changed between the two runs.
Projectpatrick-kidger/tinyio
Fix saved2026-03-14
Sharing licenceApache-2.0 · LICENSE
Change size+6 −6
What the code was meant to do, written into the code itself as a save note
Yielding already-started (but not yet completed, and not yet seen by the loop) generators will now correctly raise an error.
The change
| 228 | 228 | for out_i in out: | |
| 229 | 229 | if isinstance(out_i, Generator): | |
| 230 | 230 | if out_i not in self._results.keys() and out_i not in waiting_on.keys(): | |
| 231 | - | if inspect.getgeneratorstate(out_i) == inspect.GEN_CLOSED: | |
| 232 | - | todo.coro.throw(_already_finished(out_i)) | |
| 231 | + | if inspect.getgeneratorstate(out_i) != inspect.GEN_CREATED: | |
| 232 | + | todo.coro.throw(_already_started(out_i)) | |
| 233 | 233 | queue.appendleft(_Todo(out_i, None)) | |
| 234 | 234 | waiting_on[out_i] = [] | |
| 235 | 235 | else: | |
| ⋯ | |||
| 245 | 245 | elif out_i in waiting_on.keys(): | |
| 246 | 246 | waiting_on[out_i].append(waiting_for) | |
| 247 | 247 | else: | |
| 248 | - | if inspect.getgeneratorstate(out_i) == inspect.GEN_CLOSED: | |
| 249 | - | todo.coro.throw(_already_finished(out_i)) | |
| 248 | + | if inspect.getgeneratorstate(out_i) != inspect.GEN_CREATED: | |
| 249 | + | todo.coro.throw(_already_started(out_i)) | |
| 250 | 250 | queue.appendleft(_Todo(out_i, None)) | |
| 251 | 251 | waiting_on[out_i] = [waiting_for] | |
| 252 | 252 | elif isinstance(out_i, _Wait): | |
| ⋯ | |||
| 595 | 595 | return RuntimeError(msg) | |
| 596 | 596 | ||
| 597 | 597 | ||
| 598 | - | def _already_finished(out): | |
| 598 | + | def _already_started(out): | |
| 599 | 599 | return RuntimeError( | |
| 600 | - | f"The coroutine `{out}` has already finished. However it has not been seen by the `tinyio` loop before and as " | |
| 600 | + | f"The coroutine `{out}` has already started. However it has not been seen by the `tinyio` loop before and as " | |
| 601 | 601 | "such does not have any result associated with it." | |
| 602 | 602 | ) | |
| 603 | 603 | ||
The check that tells the two apart
fail→pass·tests/test_core.py::test_yield_finished_coroutine[bare]
fail→pass·tests/test_core.py::test_yield_finished_coroutine[list]
fail→pass·tests/test_core.py::test_yield_finished_coroutine[set]
fail→pass·tests/test_core.py::test_yield_started_generator[bare]
fail→pass·tests/test_core.py::test_yield_started_generator[list]
fail→pass·tests/test_core.py::test_yield_started_generator[set]
Check file tests/test_core.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.
Origin and history
The code before ite43ae61239c188dc7063c38b7131e21be6dd1d21
Broken version dated2026-03-14
Moduletinyio._core
Units changedLoop
Fingerprint196539643abedf5d
Checked2026-08-18 by goldset/0.1
Every field above is generated by our program. None of it is written by hand.