Skip to content

Enums with default values generate incorrect field type and to_dict implementation #373

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
joshzana opened this issue Mar 31, 2021 · 2 comments
Labels
🐞bug Something isn't working

Comments

@joshzana
Copy link

Describe the bug
We have several Enums in our API spec, and models that include fields of that enum type. Sometimes, we set default values on those enum fields. In those cases, the generated code in to_dict is incorrect and cannot be used to POST entities to our API.

To Reproduce
Steps to reproduce the behavior:
Add this code to a main.py file

from typing import Optional, Union, Dict
from fastapi import FastAPI
from pydantic import BaseModel
from enum import Enum

from starlette.responses import Response

app = FastAPI()

class ItemType(str, Enum):
    RATIO = "ratio"
    CURRENCY = "currency"

class ItemResource(BaseModel):
    id: int
    optional_id: Optional[int]
    id_with_default: int = 42

    item_type: ItemType
    optional_item_type: Optional[ItemType]
    item_type_with_default: ItemType = ItemType.RATIO

@app.post("/")
def write_item(model: ItemResource):
    return Response(status_code=201)

Run the code with uvicorn main:app &
Generate an sdk with openapi-python-client generate --url http://localhost:8000/openapi.json
Open the generated item_resource.py

Expected behavior
item_type_with_default should look like:
item_type_with_default: Union[Unset, ItemType] = ItemType.RATIO

to_dict should have code like:

item_type_with_default = self.item_type_with_default
if item_type_with_default is not UNSET:
    field_dict["item_type_with_default"] = item_type_with_default

Actual behavior
item_type_with_default looks like:
item_type_with_default: Union[Unset, None] = UNSET

to_dict has code like:

item_type_with_default = None
if item_type_with_default is not UNSET:
    field_dict["item_type_with_default"] = item_type_with_default

Since self.item_type_with_default is never accessed, the caller has no way to actually provide a value to the server.
You can see the code in there for id_with_default, an int field with default that does the right thing.

OpenAPI Spec File

{"openapi":"3.0.2","info":{"title":"FastAPI","version":"0.1.0"},"paths":{"/":{"post":{"summary":"Write Item","operationId":"write_item__post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemResource"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"title":"HTTPValidationError","type":"object","properties":{"detail":{"title":"Detail","type":"array","items":{"$ref":"#/components/schemas/ValidationError"}}}},"ItemResource":{"title":"ItemResource","required":["id","item_type"],"type":"object","properties":{"id":{"title":"Id","type":"integer"},"optional_id":{"title":"Optional Id","type":"integer"},"id_with_default":{"title":"Id With Default","type":"integer","default":42},"item_type":{"$ref":"#/components/schemas/ItemType"},"optional_item_type":{"$ref":"#/components/schemas/ItemType"},"item_type_with_default":{"allOf":[{"$ref":"#/components/schemas/ItemType"}],"default":"ratio"}}},"ItemType":{"title":"ItemType","enum":["ratio","currency"],"type":"string","description":"An enumeration."},"ValidationError":{"title":"ValidationError","required":["loc","msg","type"],"type":"object","properties":{"loc":{"title":"Location","type":"array","items":{"type":"string"}},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}}}}}}

Desktop:

  • OS: macOS 11.2.2
  • Python Version: 3.8.6
  • openapi-python-client version 0.8.0
  • fast-api version 0.62.0
@joshzana joshzana added the 🐞bug Something isn't working label Mar 31, 2021
@joshzana
Copy link
Author

Just found #362 which is a likely dupe. Sorry I didn't find it earlier.
Installing from main branch seems to address the issue.

I get

    item_type_with_default: Union[Unset, ItemType] = UNSET

and

        item_type_with_default: Union[Unset, str] = UNSET
        if not isinstance(self.item_type_with_default, Unset):
            item_type_with_default = self.item_type_with_default.value

and

        if item_type_with_default is not UNSET:
            field_dict["item_type_with_default"] = item_type_with_default

Sweet! Can we get a pip release to make it easier to consume the fix?

@emann
Copy link
Collaborator

emann commented Mar 31, 2021

Thanks for the follow up! I'll close this issue then.

We'll likely be putting out a bugfix release in the next few weeks. As mentioned in the README, pipx is awesome and I'd recommend using it to install/run the package in general, not just in times when you need to run from main.

@emann emann closed this as completed Mar 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐞bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants