Title: Improve UX for mocking dataclasses that are problematic to instantiate · Issue #124176 · python/cpython · GitHub
Open Graph Title: Improve UX for mocking dataclasses that are problematic to instantiate · Issue #124176 · python/cpython
X Title: Improve UX for mocking dataclasses that are problematic to instantiate · Issue #124176 · python/cpython
Description: Feature or enhancement Proposal: Passing instance=True to create_autospec misses fields without default values, even when the given spec is a dataclass object: >>> from dataclasses import dataclass >>> @dataclass ... class Example: ... a...
Open Graph Description: Feature or enhancement Proposal: Passing instance=True to create_autospec misses fields without default values, even when the given spec is a dataclass object: >>> from dataclasses import dataclass...
X Description: Feature or enhancement Proposal: Passing instance=True to create_autospec misses fields without default values, even when the given spec is a dataclass object: >>> from dataclasses import ...
Opengraph URL: https://github.com/python/cpython/issues/124176
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Improve UX for mocking dataclasses that are problematic to instantiate","articleBody":"# Feature or enhancement\r\n\r\n### Proposal:\r\n\r\nPassing `instance=True` to `create_autospec` misses fields without default values, even when the given spec is a `dataclass` object:\r\n\r\n```python\r\n\u003e\u003e\u003e from dataclasses import dataclass\r\n\u003e\u003e\u003e @dataclass\r\n... class Example:\r\n... a: int\r\n... b: int = 0\r\n... def sum_fields(self):\r\n... return self.a + self.b\r\n...\r\n\u003e\u003e\u003e from unittest.mock import create_autospec\r\n\u003e\u003e\u003e mock_instance = create_autospec(Example(1))\r\n\u003e\u003e\u003e mock_instance_from_class = create_autospec(Example, instance=True)\r\n\u003e\u003e\u003e set(dir(mock_instance)) - set(dir(mock_instance_from_class))\r\n{'a'}\r\n```\r\n\r\nThis is despite dataclass definitions making their field information readily available for introspection on the class object (without requiring instantiation):\r\n\r\n```python\r\n\u003e\u003e\u003e from dataclasses import fields\r\n\u003e\u003e\u003e [(field.name, field.type) for field in fields(Example)]\r\n[('a', \u003cclass 'int'\u003e), ('b', \u003cclass 'int'\u003e)]\r\n```\r\n\r\nA similar problem occurs if the dataclass uses `__post_init__` to set attributes that are not otherwise set:\r\n\r\n```python\r\n\u003e\u003e\u003e from dataclasses import dataclass, field\r\n\u003e\u003e\u003e @dataclass\r\n... class PostInitExample:\r\n... a: int = field(init=False)\r\n... b: int = field(init=False)\r\n... def __post_init__(self):\r\n... self.a = self.b = 1\r\n...\r\n\u003e\u003e\u003e mock_post_init_class = create_autospec(Example)\r\n\u003e\u003e\u003e mock_post_init_class = create_autospec(PostInitExample)\r\n\u003e\u003e\u003e mock_post_init_instance = create_autospec(PostInitExample())\r\n\u003e\u003e\u003e set(dir(mock_post_init_instance)) - set(dir(mock_post_init_class()))\r\n{'b', 'a'}\r\n```\r\n\r\nWhile for most dataclasses it is straightforward to instantiate a specific instance and derive the mock autospec from that, this may not be desirable (or even feasible) if the dataclass requires references to real external resources to create a real instance.\r\n\r\nThere are various potential workarounds available for this functional gap, but they're all relatively clumsy, and come with their own problems (like not being able to use `spec_set=True` if the missing fields are added manually, or not handling defined methods properly if setting an explicit list of fields instead of using `autospec`, or still not adding the fields only defined in `__post_init__` if instantiating a class mock).\r\n\r\nBy contrast, if `create_autospec` were to be made explicitly aware of data classes, it could do a pass over `dataclasses.fields(spec)` and use the type information to fill in any missing fields that don't have class level default values set.\r\n\r\n### Has this already been discussed elsewhere?\r\n\r\nThis is a minor feature, which does not need previous discussion elsewhere\r\n\r\n### Links to previous discussion of this feature:\r\n\r\nPreviously filed here, but closed on the basis of `create_autospec` covering the use case: https://github.com/python/cpython/issues/80761\r\n\r\nThis is only true if the dataclass can be readily instantiated, hence this feature request.\r\n\r\nThere is also some previous discussion (and assorted attempted workarounds with various flaws) on this Stack Overflow question: https://stackoverflow.com/questions/51640505/how-to-use-spec-when-mocking-data-classes-in-python\n\n\u003c!-- gh-linked-prs --\u003e\n### Linked PRs\n* gh-124429\n* gh-124724\n\u003c!-- /gh-linked-prs --\u003e\n","author":{"url":"https://github.com/ncoghlan","@type":"Person","name":"ncoghlan"},"datePublished":"2024-09-17T14:41:16.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":6},"url":"https://github.com/124176/cpython/issues/124176"}
| 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:d1d3c872-d68b-1a4d-47fe-4cce37dce2b9 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | D70E:370C10:DE5339:130B986:6A55C4ED |
| html-safe-nonce | b6e71d95b6b6ca7fe0fe95c61c71a3d673e82a9f73bb068116f22bd750fd40bf |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJENzBFOjM3MEMxMDpERTUzMzk6MTMwQjk4Njo2QTU1QzRFRCIsInZpc2l0b3JfaWQiOiI3Njk1MzI3NjQzNzIyNjk1OTE3IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 923603d7dc72cbe525144bed76abbb4759e57be5318304c892e59ca044d837d1 |
| hovercard-subject-tag | issue:2531353865 |
| 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/124176/issue_layout |
| twitter:image | https://opengraph.githubassets.com/ed1a916da3a8aa36a625e7bdc0c41c5978dfc8d3715c99477a72cd0de9128adf/python/cpython/issues/124176 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/ed1a916da3a8aa36a625e7bdc0c41c5978dfc8d3715c99477a72cd0de9128adf/python/cpython/issues/124176 |
| og:image:alt | Feature or enhancement Proposal: Passing instance=True to create_autospec misses fields without default values, even when the given spec is a dataclass object: >>> from dataclasses import dataclass... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | ncoghlan |
| hostname | github.com |
| expected-hostname | github.com |
| None | b5665c84831ed9ac4fb79519c16c9c5580ba8092fb8bb6e3e72972ec7197348e |
| 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 | 8f8e1726192df8dce16872ceb503336c12e9ae78 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width