`oneOf` inside `allOf` is ignored during code generation
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Accessibilité débutants
- 35/100
Piste de recherche
Reproduisez le problème avec la spécification OpenAPI fournie et examinez la gestion par le générateur des schémas allOf et oneOf imbriqués ; aucun fichier source ni test n'est indiqué dans le rapport. Le travail est terminé lorsque la représentation générée de AnimalAttributes conserve les champs communs et expose chaque variante de oneOf avec des attributs typés, au lieu de les placer dans additional_properties.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
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 generated class, but instead end up in additional_properties as untyped data.
OpenAPI Spec File
Click to expand full OpenAPI spec
openapi: 3.0.3
info:
title: AllOf + OneOf Test
version: 1.0.0
paths:
/animals/{animal_id}:
get:
operationId: get_animal
parameters:
- name: animal_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/Animal'
components:
schemas:
Animal:
type: object
required:
- id
- attributes
properties:
id:
type: string
attributes:
allOf:
- $ref: '#/components/schemas/CommonAttributes'
- oneOf:
- $ref: '#/components/schemas/DogAttributes'
- $ref: '#/components/schemas/CatAttributes'
CommonAttributes:
type: object
properties:
name:
type: string
description: Animal's name
age:
type: integer
description: Animal's age in years
DogAttributes:
type: object
properties:
breed:
type: string
description: Dog breed
is_good_boy:
type: boolean
description: Is this a good boy?
CatAttributes:
type: object
properties:
color:
type: string
description: Cat fur color
lives_remaining:
type: integer
description: Number of lives remaining (out of 9)
Key part of the spec (the problematic schema):
attributes:
allOf:
- $ref: '#/components/schemas/CommonAttributes' # name, age
- oneOf:
- $ref: '#/components/schemas/DogAttributes' # breed, is_good_boy
- $ref: '#/components/schemas/CatAttributes' # color, lives_remaining
Generated Code
The generated AnimalAttributes class only includes fields from CommonAttributes:
@_attrs_define
class AnimalAttributes:
"""
Attributes:
name (Union[Unset, str]): Animal's name
age (Union[Unset, int]): Animal's age in years
"""
name: Union[Unset, str] = UNSET
age: Union[Unset, int] = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
Click to expand full generated file
from typing import Any, TypeVar, Union
from attrs import define as _attrs_define
from attrs import field as _attrs_field
from ..types import UNSET, Unset
T = TypeVar("T", bound="AnimalAttributes")
@_attrs_define
class AnimalAttributes:
"""
Attributes:
name (Union[Unset, str]): Animal's name
age (Union[Unset, int]): Animal's age in years
"""
name: Union[Unset, str] = UNSET
age: Union[Unset, int] = UNSET
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
def to_dict(self) -> dict[str, Any]:
name = self.name
age = self.age
field_dict: dict[str, Any] = {}
field_dict.update(self.additional_properties)
field_dict.update({})
if name is not UNSET:
field_dict["name"] = name
if age is not UNSET:
field_dict["age"] = age
return field_dict
@classmethod
def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T:
d = src_dict.copy()
name = d.pop("name", UNSET)
age = d.pop("age", UNSET)
animal_attributes = cls(
name=name,
age=age,
)
animal_attributes.additional_properties = d
return animal_attributes
@property
def additional_keys(self) -> list[str]:
return list(self.additional_properties.keys())
def __getitem__(self, key: str) -> Any:
return self.additional_properties[key]
def __setitem__(self, key: str, value: Any) -> None:
self.additional_properties[key] = value
def __delitem__(self, key: str) -> None:
del self.additional_properties[key]
def __contains__(self, key: str) -> bool:
return key in self.additional_properties
Fields 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.
Expected Behavior
Since oneOf means "exactly one of", the generator should create separate classes for each variant and use a Union type:
@_attrs_define
class AnimalAttributesWithDog:
"""CommonAttributes + DogAttributes"""
name: Union[Unset, str] = UNSET
age: Union[Unset, int] = UNSET
breed: Union[Unset, str] = UNSET
is_good_boy: Union[Unset, bool] = UNSET
@_attrs_define
class AnimalAttributesWithCat:
"""CommonAttributes + CatAttributes"""
name: Union[Unset, str] = UNSET
age: Union[Unset, int] = UNSET
color: Union[Unset, str] = UNSET
lives_remaining: Union[Unset, int] = UNSET
# The actual type used in Animal
AnimalAttributes = Union[AnimalAttributesWithDog, AnimalAttributesWithCat]
Desktop (please complete the following information):
- OS: Linux (Ubuntu 22.04)
- Python Version: 3.13.5
- openapi-python-client version: 0.25.3
Additional context
Current workaround requires accessing fields via additional_properties, which loses type safety:
animal.additional_properties.get('breed') # type is Any, not str
Note 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.
- Langage dominant
- Python
- Étoiles
- 2k
- Forks
- 293
- Merge moyen
- 34 min
- PR mergées (30 j)
- 1
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de openapi-generators/openapi-python-client
-
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
-
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
-
Difficulté 3/5 1-2 jours Accessibilité débutants 72/100
openapi-generators/openapi-python-client#1451 · 1 commentaire ·
-
Difficulté 3/5 1-2 jours Accessibilité débutants 52/100
-
Difficulté 3/5 1-2 jours Accessibilité débutants 64/100
openapi-generators/openapi-python-client#1435 · 1 commentaire ·
Toutes les issues de openapi-generators/openapi-python-client
Issues similaires
-
essnmx good first issue
Difficulté 1/5 Moins d'une heure Accessibilité débutants 95/100
-
[Feature] 奇物选择添加优先级 Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
syfoud/Simulated_Scepter#174 ·
-
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
Giskard-AI/giskard-oss#2840 · 1 commentaire ·
-
A claim comment carrying the issue number is silently declined while the workflow reports success Ouvertearea: repo bug perceived difficulty: 2
Difficulté 2/5 1-3 heures Accessibilité débutants 70/100
-
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
yeti-platform/yeti#1380 ·