2

I have a base class BaseTemplateData which inherits from pydantic.BaseModel. Then, I want to have a property of the BaseTemplate class which stores a type of a child class of BaseTemplateData. I'm doing the following, but I'm getting a mypy error saying Type variable "file.path.TemplateDataType" is unbound, when I'm explicitly passing a bound parameter to the TypeVar call.

I also would like to have another class BaseTemplate2 which property doesn't store the type itself, but an instance of a child class of BaseTemplateData. Would the approach be correct?

Any help would be much appreciated. Thanks!

from typing import Type, TypeVar

from pydantic import BaseModel


class BaseTemplateData(BaseModel):
    """
    Base class for all templates.
    """


TemplateDataType = TypeVar("TemplateDataType", bound=BaseTemplateData)


class BaseTemplate(BaseModel):
    """
    Template class for email templates
    """

    data_model: Type[TemplateDataType]


class BaseTemplate2(BaseModel):
    """
    Template class for email templates 2
    """

    data_model: TemplateDataType
Dani Reinon
  • 55
  • 1
  • 9
  • Looks like a duplicate [question + answer](https://stackoverflow.com/questions/57270898/generic-for-typevar-and-iterator-or-another-generic-of-that-typevar#comment101041479_57270898) – edd Dec 29 '21 at 01:54
  • @edd That question isn't the same since the problem there is that the second TypeVar is being bounded by another TypeVar. In my case, I'm bounding it with a regular class, which should work. – Dani Reinon Dec 29 '21 at 02:03
  • Why are your templates inheriting directly from `BaseModel` instead of the documented base class `BaseTemplateData`? – chepner Dec 29 '21 at 14:14
  • They are different. Templates are pydantic models which have a property called data_model, which in case 1 should be a type of a child of BaseTemplateData, and in case 2, it should be an instance of a child of BaseTemplateData. – Dani Reinon Dec 29 '21 at 18:11

1 Answers1

0

I'm not so familiar with pythons Typing and can't imagine what you trying to solve by this code. But I don't understand why you need TemplateDataType?

Your expectations are:

I want to have a property of the BaseTemplate class which stores a type of a child class of BaseTemplateData

I also would like to have another class BaseTemplate2 which property doesn't store the type itself, but an instance of a child class of BaseTemplateData

Okay:

from typing import Type

from pydantic import BaseModel


class BaseTemplateData(BaseModel):
    """
    Base class for all templates.
    """


class ChildBaseTemplateData(BaseTemplateData):
    """
    Child class for Base class.
    """


class BaseTemplate(BaseModel):
    """
    Template class for email templates
    """

    data_model: Type[BaseTemplateData]


class BaseTemplate2(BaseModel):
    """
    Template class for email templates 2
    """

    data_model: BaseTemplateData


a = BaseTemplate()
# it is okay. Because a.data_model is a "type of a child class of BaseTemplateData"
a.data_model = ChildBaseTemplateData

b = BaseTemplate2()
# it is okay too. Because b.data_model is "an instance of a child class of BaseTemplateData"
b.data_model = ChildBaseTemplateData()

c = BaseTemplate2()
# error: Incompatible types in assignment (expression has type "str", variable has type "BaseTemplateData") 
c.data_model = "string"

Here is a good explanation about TypeVar

Also TypeVar is using with Generics.

Here is no Generics in your example

Proper usage of TypeVar will be something like:

from typing import Type, TypeVar, Generic

A = TypeVar("A", int, str)

class B(Generic[A]):
  pass

# Ok
a = B[int]

# Error: error: Value of type variable "A" of "B" cannot be "float"
b = B[float]
rzlvmp
  • 7,512
  • 5
  • 16
  • 45
  • Thanks for answering! I'll try and let you know, but this seems to make sense. My idea with TypeVar was to explicitly make a Type which demands a subclass of BaseTemplateData, but all subclasses of BaseTemplateData have BaseTamplateData type so it makes sense. – Dani Reinon Dec 29 '21 at 09:46