OpenAPITools / OpenAPITools/openapi-generator
[BUG][PYTHON] Validation on dict values with enum not working correctly
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator (example)?
- Have you tested with the latest master to confirm the issue still exists?
- Have you searched for related issues/PRs?
- What's the actual output vs expected output?
- [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
The model validation is wrong for dictionaries with values in Enums. The fields_validate_enum method is not expecting a dict as input.
openapi-generator version
Docker image: openapitools/openapi-generator-cli
Versions: v7.7.0
OpenAPI declaration file content or url
Generation Details
Generated via Docker, using the following command:
docker run --rm -v $(pwd):/api openapitools/openapi-generator-cli:v7.7.0 \
generate -g python \
-c /api/python.yml \
-i /api/openapi.yaml \
-o /api/clients/python
Here is the python.yml config file:
packageName: python_client
projectName: python-client
packageVersion: 2.2.0
hideGenerationTimestamp: true
generateSourceCodeOnly: false
mapNumberTo: Union[StrictFloat, StrictInt]
datetimeFormat: "%Y-%m-%dT%H:%M:%S%z"
dateFormat: "%Y-%m-%d"
useOneOfDiscriminatorLookup: false
library: urllib3
disallowAdditionalPropertiesIfNotPresent: true
Steps to reproduce
OS: Ubuntu 22.04
Python: 3.10.12
curl https://gist.githubusercontent.com/vcutrona/adb7571338fce6cb5c495ba4abd725f7/raw/b736a812adcaac6a118f0f7c8d714f81084b63c4/openapi.yaml -o openapi.yaml- Generate the
python.ymlfile with the config specified above docker run --rm -v $(pwd):/api openapitools/openapi-generator-cli:v7.7.0 generate -g python -c /api/python.yml -i /api/openapi.yaml -o /api/clients/python- Install the new client with
pip install -e clients/python - execute the following code snippet:
from python_client.models import MeasurementDescriptorDto
MeasurementDescriptorDto(fields={"aField": "STRING", "anotherField": "BOOLEAN"})
Exception thrown:
if value not in set(['STRING', 'BOOLEAN', 'NUMBER']):
TypeError: unhashable type: 'dict'
Related issues/PRs
Suggest a fix
- #19316
In my example (OAS 3.0), fields is a key-value dictionary (defined as documented here).
Also, the additionalProperties keyword is used to specify the type of values in that dictionary.
In my example, fields accepts strings as values, in particular only those matching an enum (i.e., "STRING", "BOOLEAN", "NUMBER").
The python generator can indeed recognize this spec, generating the MeasurementDescriptorDto class as it follows:
class MeasurementDescriptorDto(BaseModel):
"""
MeasurementDescriptorDto
""" # noqa: E501
id: Optional[StrictStr] = None
name: Optional[StrictStr] = None
description: Optional[StrictStr] = None
unit_of_measure_id: Optional[StrictStr] = Field(default=None, alias="unitOfMeasureId")
taxonomy_item_id: Optional[StrictStr] = Field(default=None, alias="taxonomyItemId")
scale_id: Optional[StrictStr] = Field(default=None, alias="scaleId")
factory_entity_model_id: Optional[StrictStr] = Field(default=None, alias="factoryEntityModelId")
categories_id: Optional[List[StrictStr]] = Field(default=None, alias="categoriesId")
functional_module_inputs_id: Optional[List[StrictStr]] = Field(default=None, alias="functionalModuleInputsId")
fields: Optional[Dict[str, StrictStr]] = None
output_maps_id: Optional[List[StrictStr]] = Field(default=None, alias="outputMapsId")
__properties: ClassVar[List[str]] = ["id", "name", "description", "unitOfMeasureId", "taxonomyItemId", "scaleId", "factoryEntityModelId", "categoriesId", "functionalModuleInputsId", "fields", "outputMapsId"]
Please note the type of fields declared as Optional[Dict[str, StrictStr]].
Given that fields is a dictionary (optional), the following validator cannot work.
Indeed, the fields_validate_enum is not expecting a dictionary as input:
@field_validator('fields')
def fields_validate_enum(cls, value):
"""Validates the enum"""
if value is None:
return value
if value not in set(['STRING', 'BOOLEAN', 'NUMBER']):
raise ValueError("must be one of enum values ('STRING', 'BOOLEAN', 'NUMBER')")
return value
The suggested PR #19316 applies the validation function to the values of the dictionary (i.e., value.values()), not to the dictionary itself (i.e., value).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start from the generated MeasurementDescriptorDto example and trace the fields_validate_enum validator in the Python generator output. Reproduce the failure with the supplied OpenAPI file and Docker command; done means dictionary values such as STRING, BOOLEAN, and NUMBER are validated without treating the dictionary itself as an enum value.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100