Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate a type from another type and change fields to optional

I have this type:

class SomeResource:
    id: int
    name: str

And I need this type:

class SomeResourceQuery:
    id: Optional[int]
    name: Optional[str]

But I'd like to avoid having to write it by hand. Is it possible to generate this SomeResourceQuery type from the SomeResource type? Just convert all the types of the fields to optional. (Update: Already optional fields can stay optional - no nested optionals.)

I plan to use this SomeResourceQuery in a repository, like this:

class SomeResourceRepository:
    def get_one_or_none(self, query: SomeResourceQuery) -> Optional[SomeResource]:
        ...

Update: Just to show what I'm thinking currently:

class SomeResource:
    id: int
    name: str


# I don't want to write this by hand:
# class SomeResourceQuery:
#     id: Optional[int]
#     name: Optional[str]

# So what can I do here to make all fields that are not already optional, optional?
SomeResourceQuery = type("SomeResourceQuery", SomeResource) # What to do here?
like image 848
L42 Avatar asked Oct 19 '25 02:10

L42


1 Answers

You can use the type constructor to construct the new type with the appropriate annotations.

def construct_query_class(cls: type) -> type:
    annotations = {key: typing.Optional[value]
                    for key, value in cls.__annotations__.items()}

    return dataclasses.dataclass(type(cls.__name__ + 'Query', (),
                                      {'__annotations__': annotations}))

class SomeResource:
    id: int
    name: str

SomeResourceQuery = construct_query_class(SomeResource) # type: typing.Any
like image 153
Daniel Walker Avatar answered Oct 20 '25 15:10

Daniel Walker