Title: `oneOf` inside `allOf` is ignored during code generation · Issue #1328 · openapi-generators/openapi-python-client · GitHub
Open Graph Title: `oneOf` inside `allOf` is ignored during code generation · Issue #1328 · openapi-generators/openapi-python-client
X Title: `oneOf` inside `allOf` is ignored during code generation · Issue #1328 · openapi-generators/openapi-python-client
Description: Describe the bug When using allOf with a nested oneOf, the code generator only processes the first schema in the allOf list and ignores the oneOf portion. Fields defined in the oneOf schemas are not included as typed attributes in the ge...
Open Graph Description: Describe the bug When using allOf with a nested oneOf, the code generator only processes the first schema in the allOf list and ignores the oneOf portion. Fields defined in the oneOf schemas are no...
X Description: Describe the bug When using allOf with a nested oneOf, the code generator only processes the first schema in the allOf list and ignores the oneOf portion. Fields defined in the oneOf schemas are no...
Opengraph URL: https://github.com/openapi-generators/openapi-python-client/issues/1328
X: @github
Domain: patch-diff.githubusercontent.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"`oneOf` inside `allOf` is ignored during code generation","articleBody":"**Describe the bug**\n\nWhen using `allOf` with a nested `oneOf`, the code generator only processes the first schema in the `allOf` list and ignores the `oneOf` portion. Fields defined in the `oneOf` schemas are not included as typed attributes in the generated class, but instead end up in `additional_properties` as untyped data.\n\n**OpenAPI Spec File**\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand full OpenAPI spec\u003c/summary\u003e\n\n```yaml\nopenapi: 3.0.3\ninfo:\n title: AllOf + OneOf Test\n version: 1.0.0\npaths:\n /animals/{animal_id}:\n get:\n operationId: get_animal\n parameters:\n - name: animal_id\n in: path\n required: true\n schema:\n type: string\n responses:\n '200':\n description: Success\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/Animal'\n\ncomponents:\n schemas:\n Animal:\n type: object\n required:\n - id\n - attributes\n properties:\n id:\n type: string\n attributes:\n allOf:\n - $ref: '#/components/schemas/CommonAttributes'\n - oneOf:\n - $ref: '#/components/schemas/DogAttributes'\n - $ref: '#/components/schemas/CatAttributes'\n\n CommonAttributes:\n type: object\n properties:\n name:\n type: string\n description: Animal's name\n age:\n type: integer\n description: Animal's age in years\n\n DogAttributes:\n type: object\n properties:\n breed:\n type: string\n description: Dog breed\n is_good_boy:\n type: boolean\n description: Is this a good boy?\n\n CatAttributes:\n type: object\n properties:\n color:\n type: string\n description: Cat fur color\n lives_remaining:\n type: integer\n description: Number of lives remaining (out of 9)\n```\n\n\u003c/details\u003e\n\nKey part of the spec (the problematic schema):\n```yaml\nattributes:\n allOf:\n - $ref: '#/components/schemas/CommonAttributes' # name, age\n - oneOf:\n - $ref: '#/components/schemas/DogAttributes' # breed, is_good_boy\n - $ref: '#/components/schemas/CatAttributes' # color, lives_remaining\n```\n\n**Generated Code**\n\nThe generated `AnimalAttributes` class only includes fields from `CommonAttributes`:\n\n```python\n@_attrs_define\nclass AnimalAttributes:\n \"\"\"\n Attributes:\n name (Union[Unset, str]): Animal's name\n age (Union[Unset, int]): Animal's age in years\n \"\"\"\n\n name: Union[Unset, str] = UNSET\n age: Union[Unset, int] = UNSET\n additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand full generated file\u003c/summary\u003e\n\n```python\nfrom typing import Any, TypeVar, Union\n\nfrom attrs import define as _attrs_define\nfrom attrs import field as _attrs_field\n\nfrom ..types import UNSET, Unset\n\nT = TypeVar(\"T\", bound=\"AnimalAttributes\")\n\n\n@_attrs_define\nclass AnimalAttributes:\n \"\"\"\n Attributes:\n name (Union[Unset, str]): Animal's name\n age (Union[Unset, int]): Animal's age in years\n \"\"\"\n\n name: Union[Unset, str] = UNSET\n age: Union[Unset, int] = UNSET\n additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)\n\n def to_dict(self) -\u003e dict[str, Any]:\n name = self.name\n\n age = self.age\n\n field_dict: dict[str, Any] = {}\n field_dict.update(self.additional_properties)\n field_dict.update({})\n if name is not UNSET:\n field_dict[\"name\"] = name\n if age is not UNSET:\n field_dict[\"age\"] = age\n\n return field_dict\n\n @classmethod\n def from_dict(cls: type[T], src_dict: dict[str, Any]) -\u003e T:\n d = src_dict.copy()\n name = d.pop(\"name\", UNSET)\n\n age = d.pop(\"age\", UNSET)\n\n animal_attributes = cls(\n name=name,\n age=age,\n )\n\n animal_attributes.additional_properties = d\n return animal_attributes\n\n @property\n def additional_keys(self) -\u003e list[str]:\n return list(self.additional_properties.keys())\n\n def __getitem__(self, key: str) -\u003e Any:\n return self.additional_properties[key]\n\n def __setitem__(self, key: str, value: Any) -\u003e None:\n self.additional_properties[key] = value\n\n def __delitem__(self, key: str) -\u003e None:\n del self.additional_properties[key]\n\n def __contains__(self, key: str) -\u003e bool:\n return key in self.additional_properties\n```\n\n\u003c/details\u003e\n\nFields from `DogAttributes` and `CatAttributes` are not present as typed attributes. When parsing JSON responses containing these fields (e.g., `breed`, `is_good_boy`), they end up in `additional_properties` as untyped data.\n\n**Expected Behavior**\n\nSince `oneOf` means \"exactly one of\", the generator should create separate classes for each variant and use a Union type:\n\n```python\n@_attrs_define\nclass AnimalAttributesWithDog:\n \"\"\"CommonAttributes + DogAttributes\"\"\"\n name: Union[Unset, str] = UNSET\n age: Union[Unset, int] = UNSET\n breed: Union[Unset, str] = UNSET\n is_good_boy: Union[Unset, bool] = UNSET\n\n@_attrs_define\nclass AnimalAttributesWithCat:\n \"\"\"CommonAttributes + CatAttributes\"\"\"\n name: Union[Unset, str] = UNSET\n age: Union[Unset, int] = UNSET\n color: Union[Unset, str] = UNSET\n lives_remaining: Union[Unset, int] = UNSET\n\n# The actual type used in Animal\nAnimalAttributes = Union[AnimalAttributesWithDog, AnimalAttributesWithCat]\n```\n\n**Desktop (please complete the following information):**\n - OS: Linux (Ubuntu 22.04)\n - Python Version: 3.13.5\n - openapi-python-client version: 0.25.3\n\n**Additional context**\n\nCurrent workaround requires accessing fields via `additional_properties`, which loses type safety:\n```python\nanimal.additional_properties.get('breed') # type is Any, not str\n```\n\nNote that `DogAttributes` and `CatAttributes` are generated as separate model files, but they are not merged into the `AnimalAttributes` class as expected from the `allOf` + `oneOf` combination.\n","author":{"url":"https://github.com/tsuga","@type":"Person","name":"tsuga"},"datePublished":"2025-10-06T11:40:01.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/1328/openapi-python-client/issues/1328"}
| 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:05c77731-0a0f-47fb-f240-2321f797d8e0 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | AF3A:130E42:289C86:32DD06:697FE205 |
| html-safe-nonce | e4f4d3dfc9b148ba06b3aa09baddcd830c95df684f9d199ac0ff015458e1fd81 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBRjNBOjEzMEU0MjoyODlDODY6MzJERDA2OjY5N0ZFMjA1IiwidmlzaXRvcl9pZCI6IjY0OTA0ODUyNzE1OTc5MzMwNjEiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | b9db732672058c5295858ca1809539ef35b8db1dc797fbb78c140171bdf9b6d0 |
| hovercard-subject-tag | issue:3486868351 |
| 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/openapi-generators/openapi-python-client/1328/issue_layout |
| twitter:image | https://opengraph.githubassets.com/6a513bf768bd938dd6a29c036f1584d796c502989e493b64499434625e3f6dad/openapi-generators/openapi-python-client/issues/1328 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/6a513bf768bd938dd6a29c036f1584d796c502989e493b64499434625e3f6dad/openapi-generators/openapi-python-client/issues/1328 |
| og:image:alt | Describe the bug When using allOf with a nested oneOf, the code generator only processes the first schema in the allOf list and ignores the oneOf portion. Fields defined in the oneOf schemas are no... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | tsuga |
| hostname | github.com |
| expected-hostname | github.com |
| None | 60279d4097367e16897439d16d6bbe4180663db828c666eeed2656988ffe59f6 |
| turbo-cache-control | no-preview |
| go-import | github.com/openapi-generators/openapi-python-client git https://github.com/openapi-generators/openapi-python-client.git |
| octolytics-dimension-user_id | 84925606 |
| octolytics-dimension-user_login | openapi-generators |
| octolytics-dimension-repository_id | 240776275 |
| octolytics-dimension-repository_nwo | openapi-generators/openapi-python-client |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 240776275 |
| octolytics-dimension-repository_network_root_nwo | openapi-generators/openapi-python-client |
| 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 | 7c85641c598ad130c74f7bcc27f58575cac69551 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width