Title: `importlib.abc.Traversable.read_text()` incompatible with `importlib.resources._functional.read_text()` usage (Python 3.13) · Issue #127012 · python/cpython · GitHub
Open Graph Title: `importlib.abc.Traversable.read_text()` incompatible with `importlib.resources._functional.read_text()` usage (Python 3.13) · Issue #127012 · python/cpython
X Title: `importlib.abc.Traversable.read_text()` incompatible with `importlib.resources._functional.read_text()` usage (Python 3.13) · Issue #127012 · python/cpython
Description: Bug report Bug description: I'm writing a custom importer and discovered that the function signature for importlib.abc.Traversable.read_text() is incompatible with the usage in importlib.resources._functional.read_text(), specifically on...
Open Graph Description: Bug report Bug description: I'm writing a custom importer and discovered that the function signature for importlib.abc.Traversable.read_text() is incompatible with the usage in importlib.resources....
X Description: Bug report Bug description: I'm writing a custom importer and discovered that the function signature for importlib.abc.Traversable.read_text() is incompatible with the usage in importlib.resour...
Opengraph URL: https://github.com/python/cpython/issues/127012
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"`importlib.abc.Traversable.read_text()` incompatible with `importlib.resources._functional.read_text()` usage (Python 3.13)","articleBody":"# Bug report\r\n\r\n### Bug description:\r\n\r\nI'm writing a custom importer and discovered that the function signature for `importlib.abc.Traversable.read_text()` is incompatible with the usage in `importlib.resources._functional.read_text()`, specifically on Python 3.13.\r\n\r\n1. `importlib.abc.Traversable.read_text()` is a concrete method; its implementation calls the `.open()` method, which is an abstract method that must be implemented. The expectation is therefore that implementing `.open()` in a Traversable subclass is sufficient for `.read_text()` to work.\r\n\r\n Note below that the `.read_text()` method is not marked as abstract, and includes only one parameter: `encoding`:\r\n\r\n https://github.com/python/cpython/blob/30aeb00d367d0cc9e5a7603371636cddea09f1c0/Lib/importlib/resources/abc.py#L84-L90\r\n\r\n2. Application code that attempts to read a package resource, like `importlib.resources.read_text(module, \"resource.txt\")` ultimately leads to a call to `importlib.resources._functional.read_text()`, which attempts to call the `.read_text()` method of a Traversable subclass, but includes an `errors` parameter that doesn't exist in Traversable's default concrete method:\r\n\r\n https://github.com/python/cpython/blob/30aeb00d367d0cc9e5a7603371636cddea09f1c0/Lib/importlib/resources/_functional.py#L28-L32\r\n\r\n3. Consequently, it appears to be necessary for all Traversable subclasses to not only re-implement its concrete `.read_text()` method, but also to override its signature.\r\n\r\nI think that the Traversable `.read_text()` method signature, and the call site in `importlib.resources._functional.read_text()`, need to align with each other.\r\n\r\n**_I'd like to submit a PR for this!_** However, I would like confirmation that an `errors` parameter should be added to the `Traversable.read_text()` method.\r\n\r\nNote that adding an `errors` parameter was previously discussed in #88368.\r\n\r\n## Demonstration of TypeError bug\r\n\r\n```python\r\nimport io\r\nimport sys\r\nimport typing\r\nimport pathlib\r\nimport types\r\nimport importlib.abc\r\nimport importlib.machinery\r\nimport importlib.metadata\r\nimport importlib.resources.abc\r\n\r\n\r\nclass ExampleFinder(importlib.abc.MetaPathFinder):\r\n def find_spec(\r\n self,\r\n fullname: str,\r\n path: typing.Sequence[str] | None,\r\n target: types.ModuleType | None = None,\r\n ) -\u003e importlib.machinery.ModuleSpec | None:\r\n if fullname != \"demonstrate_error\":\r\n return None\r\n\r\n print(f\"ExampleFinder.find_spec('{fullname}')\")\r\n spec = importlib.machinery.ModuleSpec(\r\n name=fullname,\r\n loader=ExampleLoader(),\r\n is_package=True,\r\n )\r\n return spec\r\n\r\n\r\nsys.meta_path.append(ExampleFinder())\r\n\r\n\r\nclass ExampleLoader(importlib.abc.Loader):\r\n def exec_module(self, module: types.ModuleType) -\u003e None:\r\n print(f\"ExampleLoader.exec_module({module})\")\r\n exec(\"\", module.__dict__)\r\n\r\n def get_resource_reader(self, fullname: str) -\u003e \"ExampleTraversableResources\":\r\n print(f\"ExampleLoader.get_resource_reader('{fullname}')\")\r\n return ExampleTraversableResources(fullname)\r\n\r\n\r\nclass ExampleTraversableResources(importlib.resources.abc.TraversableResources):\r\n def __init__(self, fullname: str) -\u003e None:\r\n self.fullname = fullname\r\n\r\n def files(self) -\u003e \"ExampleTraversable\":\r\n print(\"ExampleTraversableResources.files()\")\r\n return ExampleTraversable(self.fullname)\r\n\r\n\r\n# ----------------------------------------------------------------------------\r\n# ExampleTraversable implements all five of the Traversable abstract methods.\r\n# Specifically, it is expected that implementing `.open()` will be sufficient,\r\n# but this will not be the case.\r\n#\r\n\r\nclass ExampleTraversable(importlib.resources.abc.Traversable):\r\n def __init__(self, path: str):\r\n self._path = path\r\n\r\n def iterdir(self) -\u003e typing.Iterator[\"ExampleTraversable\"]:\r\n yield ExampleTraversable(\"resource.txt\")\r\n\r\n def is_dir(self) -\u003e bool:\r\n return False\r\n\r\n def is_file(self) -\u003e bool:\r\n return True\r\n\r\n def open(self, mode='r', *args, **kwargs) -\u003e typing.IO[typing.AnyStr]:\r\n return io.StringIO(\"Nice! The call to .read_text() succeeded!\")\r\n\r\n # Uncomment this `.read_text()` method to make `.read_text()` calls work.\r\n # It overrides the `Traversable.read_text()` signature.\r\n #\r\n # def read_text(self, encoding: str | None, errors: str | None) -\u003e str:\r\n # print(f\"ExampleTraversable.read_text('{encoding}', '{errors}')\")\r\n # return str(super().read_text(encoding))\r\n\r\n @property\r\n def name(self) -\u003e str:\r\n return pathlib.PurePosixPath(self._path).name\r\n\r\n\r\n# -------------------------------------------------------------------------------\r\n# Everything above allows us to import this hard-coded module\r\n# and demonstrate a TypeError lurking in the Traversable.read_text() signature.\r\n#\r\n\r\nimport demonstrate_error\r\n\r\n\r\n# The next line will raise a TypeError.\r\n# `importlib/resources/_functional.py:read_text()` calls `Traversable.read_text()`\r\n# with an `errors` argument that is not supported by the default concrete method.\r\nprint(importlib.resources.read_text(demonstrate_error, \"resource.txt\"))\r\n```\r\n\r\n### CPython versions tested on:\r\n\r\n3.13\r\n\r\n### Operating systems tested on:\r\n\r\nLinux","author":{"url":"https://github.com/kurtmckee","@type":"Person","name":"kurtmckee"},"datePublished":"2024-11-19T13:28:01.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":13},"url":"https://github.com/127012/cpython/issues/127012"}
| 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:ea833325-ab63-d952-fcbf-b88920994e14 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | EBD6:178041:41C189:5B8862:696A6A3A |
| html-safe-nonce | 01a0f4a410822a02f1fc6eda46b48bd5362b94b0b35c3e368379f98ed46f7089 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFQkQ2OjE3ODA0MTo0MUMxODk6NUI4ODYyOjY5NkE2QTNBIiwidmlzaXRvcl9pZCI6IjQ5NzE5NDIzOTIzMTEyMTI2MDIiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 6d72359780deecd9b562937484576b3373b0ed8a50f56fc092bfdd74395fbe42 |
| hovercard-subject-tag | issue:2672194534 |
| 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/127012/issue_layout |
| twitter:image | https://opengraph.githubassets.com/cd4b0bfa949d7348ac97172c35d0638b343bdadd0eded6ab3305bf7891bc1499/python/cpython/issues/127012 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/cd4b0bfa949d7348ac97172c35d0638b343bdadd0eded6ab3305bf7891bc1499/python/cpython/issues/127012 |
| og:image:alt | Bug report Bug description: I'm writing a custom importer and discovered that the function signature for importlib.abc.Traversable.read_text() is incompatible with the usage in importlib.resources.... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | kurtmckee |
| hostname | github.com |
| expected-hostname | github.com |
| None | 6fea32d5b7276b841b7a803796d9715bc6cfb31ed549fdf9de2948ac25d12ba6 |
| 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 | f2d9f6432a5a115ec709295ae70623f33bb80aee |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width