Title: Support non-sequence iterables in the `ExceptionGroup` API, or document the design decision · Issue #129867 · python/cpython · GitHub
Open Graph Title: Support non-sequence iterables in the `ExceptionGroup` API, or document the design decision · Issue #129867 · python/cpython
X Title: Support non-sequence iterables in the `ExceptionGroup` API, or document the design decision · Issue #129867 · python/cpython
Description: Feature or enhancement Proposal: Currently, the ExceptionGroup API only supports sequences of exceptions to its second parameter excs. This ticket suggests either: additively changing the API to support non-sequence iterables as inputs a...
Open Graph Description: Feature or enhancement Proposal: Currently, the ExceptionGroup API only supports sequences of exceptions to its second parameter excs. This ticket suggests either: additively changing the API to su...
X Description: Feature or enhancement Proposal: Currently, the ExceptionGroup API only supports sequences of exceptions to its second parameter excs. This ticket suggests either: additively changing the API to su...
Opengraph URL: https://github.com/python/cpython/issues/129867
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Support non-sequence iterables in the `ExceptionGroup` API, or document the design decision","articleBody":"# Feature or enhancement\n\n### Proposal:\n\nCurrently, the `ExceptionGroup` API only supports _sequences_ of exceptions to its second parameter `excs`.\nThis ticket suggests _either_:\n- additively changing the API to support non-sequence iterables as inputs as well.\n\nor\n- documenting why only sequences are supported.\n\nCurrently, this Python code would work:\n\n```python\nExceptionGroup(\"list\", [ValueError(), AttributeError()]) # OK\n\nExceptionGroup(\"tuple\", (ValueError(), AttributeError())) # OK\n\nclass Niche:\n def __getitem__(self, i):\n if i == 0:\n return ValueError()\n if i == 1:\n return AttributeError()\n raise StopIteration\n\nExceptionGroup(\"niche\", Niche()) # OK\n```\n\n\u003e [!note]\n\u003e AFAIK, `ExceptionGroup` objects do not store the sequence passed to them, _unless_ it's a tuple object (excluding tuple subclasses). They export a new tuple (created from the passed-in sequence) or passed-in tuple [via `.exceptions`](https://docs.python.org/3/library/exceptions.html#BaseExceptionGroup.exceptions).\n\u003e Quick illustration:\n\u003e ```py\n\u003e assert ExceptionGroup(\"\", excs := [ValueError()]).exceptions is not excs # OK\n\u003e assert ExceptionGroup(\"\", excs := (ValueError(),)).exceptions is excs # OK\n\u003e assert ExceptionGroup(\"\", excs := type(\"\", (tuple,), {})([ValueError(),])).exceptions is not excs # OK\n\u003e ```\n\nThis is a minimal example of a use case I would desire, which is not currently supported:\n\n```py\ndef cb1():\n raise ValueError\n\ndef cb2():\n raise AttributeError\n\nerrors = {}\ncallbacks = {\"module1\": cb1, \"module2\": cb2}\nfor mod, cb in callbacks.items():\n try:\n cb()\n except Exception as exc:\n errors[mod] = exc\n\nif errors:\n raise ExceptionGroup(f\"got errors in {', '.join(errors)}\", errors.values())\n```\n\n\u003e [!important]\n\u003e **While this _can_ be simply worked around by converting the values' view into a sequence, the question is more fundamental: _why_?**\n\nThere are some [other variants of this on GitHub](https://github.com/search?q=%2FExceptionGroup%5C%28.*%2C+%28list%7Ctuple%29%5C%28%2F\u0026type=code), too (including my humble one).\n\nIt was an intentional decision to only support sequences, justifying the very first part of the constructor test:\nhttps://github.com/python/cpython/blob/1bccd6c34f82f8373c320792323bfd7f7a328bc7/Lib/test/test_exception_group.py#L39-L42\n\nBefore writing this issue, I did a research in some places that seemed like they could explain why only sequences made a cut. Namely, I:\n- read the [docs of built-in exceptions](https://docs.python.org/3/library/exceptions.html#exception-groups),\n- [checked the PEP](https://peps.python.org/pep-0654),\n- skimmed through [the relevant PR](https://github.com/python/cpython/pull/28569),\n- read the discussions in [python/exceptiongroups](https://github.com/python/exceptiongroups),\n- searched the issue tracker.\n\nI didn't have the time to read them very in depth, so I might have overlooked something; I only found this thread relevant:\n- https://github.com/python/exceptiongroups/pull/13#issuecomment-754375503\n\nWhich leads me to think that supporting `Iterable` was [initially planned](https://github.com/python/exceptiongroups/issues/6#issue-730576441) (the author meant `Iterable[Exception]` instead of `Iterable[ExceptionGroup]`), but then implicitly ignored for the sake of predicted use cases only being with sequences (lists/tuples).\nPlease note that the considerations about variadic constructor of `BaseExceptionGroup` are not relevant to this ticket.\n\nBefore writing this, I also reached out to @ZeroIntensity and @Eclips4 to discuss the topic.\n\n@Eclips4 confirmed that he saw no hard requirement for the exception sequence to be a sequence specifically, and applying this simple patch\n\n```diff\ndiff --git a/Objects/exceptions.c b/Objects/exceptions.c\nindex 154cde93168..f97eb33953f 100644\n--- a/Objects/exceptions.c\n+++ b/Objects/exceptions.c\n@@ -871,7 +871,8 @@ BaseExceptionGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\n return NULL;\n }\n\n- if (!PySequence_Check(exceptions)) {\n+ PyTypeObject *t = Py_TYPE(exceptions);\n+ if (t-\u003etp_iter == NULL) {\n PyErr_SetString(\n PyExc_TypeError,\n \"second argument (exceptions) must be a sequence\");\n```\n\n[only causes `test_bad_EG_construction__bad_excs_sequence` to fail](https://pastebin.com/rg3CTLHi).\n\nCC @iritkatriel @gvanrossum @1st1\n\n\n### Has this already been discussed elsewhere?\n\nThis is a minor feature, which does not need previous discussion elsewhere\n\n### Links to previous discussion of this feature:\n\n_No response_","author":{"url":"https://github.com/johnslavik","@type":"Person","name":"johnslavik"},"datePublished":"2025-02-08T19:59:47.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":5},"url":"https://github.com/129867/cpython/issues/129867"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:ba9a99d0-f064-0088-ea7f-cd8d725b4348 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | BBD8:228CBB:55EE66:792697:696A0E24 |
| html-safe-nonce | 0038bc3017602937a13cbf9b8e02b3ec74f9247b2d673ba603c32d92bcdd3b72 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCQkQ4OjIyOENCQjo1NUVFNjY6NzkyNjk3OjY5NkEwRTI0IiwidmlzaXRvcl9pZCI6IjY2MjU5Njk5MDMyNzk2NzI4NjgiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | c44bdf6cc3e809f0f22a27a00ff2e2c263b160806e0f48cbc532b07b14d5fd68 |
| hovercard-subject-tag | issue:2840236126 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/129867/issue_layout |
| twitter:image | https://opengraph.githubassets.com/497cdcb41720b403bc5a1acf370fbb397e8f333481d4628c7d8ae967bb4a98c7/python/cpython/issues/129867 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/497cdcb41720b403bc5a1acf370fbb397e8f333481d4628c7d8ae967bb4a98c7/python/cpython/issues/129867 |
| og:image:alt | Feature or enhancement Proposal: Currently, the ExceptionGroup API only supports sequences of exceptions to its second parameter excs. This ticket suggests either: additively changing the API to su... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | johnslavik |
| hostname | github.com |
| expected-hostname | github.com |
| None | 699227a00bbb7fe1eec276d2ae1c3a93068bc5ba483bd9dc4b2a27a8f4f2f595 |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 7266b2d935baa1c6474b16dd9feaa5ca30607261 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width