Search code examples
pythonpydantic

General way to convert python type to descriptive string?


I'm using pydantic to generate these sweet json objects which describe the attributes:

from pydantic import BaseModel, Field

class MyModel(BaseModel):
    argument_1: int = Field(..., description="desc.")

print(MyModel.model_json_schema())

# Outputs:
{'properties': {'argument_1': {'description': 'desc.', 'title': 'Argument 1', 'type': 'integer'}}, 'required': ['argument_1'], 'title': 'MyModel', 'type': 'object'}

It clearly states the types each property. ('type': 'integer')

But now I also want to get the return type of a function in the same form. I've tried a few things and the closest I get is the literal return type.

from typing import get_type_hints


def get_return_type(obj):
    type_hints = get_type_hints(obj)
    return type_hints.get("return", "Unknown")

def my_func() -> int:
    return 10

print(get_return_type(my_func))
print(my_func.__annotations__.get("return"))
print(my_func.__annotations__.get("return").__name__)

# Outputs:
<class 'int'>
<class 'int'>
int

I wish to get the return value the same way that Pydantic gives me the type of a schema's attributes, like: "integer", "number", "string", "array" etc...

Looking at the Pydantic docs didn't make me much wiser either

or maybe im blind :(. Though while looking though the code of GenerateJsonSchema I did notice that it can convert types to a descriptive string, but I have no clue how to use it for my case.

This comes close, but isn't quite it.

Is there a general way to achieve this? Or maybe a way to use Pydantic for this? Or will I have to write my own custom mapping?


Solution

  • So, Pydantic doesn't offer a native way to do this, but there is a way you could go via pydantic to save writing your own mapper, using create_model:

    from inspect import signature
    from typing import Any, Callable
    
    from pydantic import create_model
    
    def return_annotation_extract(f: Callable[..., Any]) -> str:
        t = signature(f).return_annotation
        p_model = create_model('dummy', dummy_field=(t,...))
        return p_model.model_json_schema()['properties']['dummy_field']['type']
    
    def my_func() -> int:
        return 10
    
    print(return_annotation_extract(my_func))
    

    Here I use signature to extract the return annotation but the ways you suggested would also work - the signature library is just helpful for extracting all info about a function, including the function parameters. Hope this is useful!