Background
I'm writing a system for parsing a configuration file that contains different sections. Each section can have a range of entries, each of which has a different logic for how to parse the data in the config file. I've encapsulated each section into a class (all of which derive from a base section class). For each section class, I also have a companion parser class, which acts as a factory for that specific section. So each parser will receive the loaded configuration file, parse the its section and return the corresponding section class type.
In order to allow users to either append more sections to the file or override base sections, I need to return a table with all the base parsers. The idea is that the users can tack on more parsers for their custom sections, or override a specific parser by deriving from it and modifying the parsing code as needed. This can also include returning a derived class from the original section. To do this, I need to return a dictionary mapping the name of each parser to the corresponding parser. The issue I'm having is figuring out how to type hint this function correctly.
Minimal Example
Here's a simplified example of what I'm trying to do. First, the section classes:
@dataclass
class BaseSection:
extra: int = 0
@dataclass
class ASection(BaseSection):
a: int = 0
@dataclass
class BSection(BaseSection):
b: int = 0
Now the parsers:
T = TypeVar("T", bound=BaseSection)
class BaseSectionParser(Generic[T]):
def parse(self, data: str) -> Optional[T]:
if len(data) == 0:
return None
return self._get_data(data)
@abstractmethod
def _get_data(self, data: str) -> T:
pass
class ASectionParser(BaseSectionParser[ASection]):
def _get_data(self, data: str) -> ASection:
ret = ASection()
if data == "a":
ret.a = 1
return ret
class BSectionParser(BaseSectionParser[BSection]):
def _get_data(self, data: str) -> BSection:
ret = BSection()
if data == "b":
ret.b = 2
return ret
Finally, here's the function that returns the dictionary:
def get_parsers() -> dict: # <- What do I put here for a type hint?
return {
"a": ASectionParser,
"b": BSectionParser,
}
Things I've Tried
So far, I have tried the following for type hints:
dict
,dict[str, Any]
,dict[str, type]
: the simplest options. Mypy gives no errors, but obviously they contain no information about what the returned dictionary is. I know these work, but I'm wondering if there's a better way to type hint this.dict[str, BaseSectionParser]
: Mypy gives the same error for both lineserror: Dict entry 0 has incompatible type "str": "type[ASectionParser]"; expected "str": "BaseSectionParser[Any]"
dict[str, BaseSectionParser[T]]
: Mypy also gives errors, only difference is it changes theAny
argument toT
.
I'm honestly stumped on what to do here. How would I type hint this in a way that conveys the notion that the function returns a "dictionary of strings to types derived from BaseSectionParser"?
Edit 1
Expanded the tried type hints from dict
to include dict[str, type]
and dict[str, Any]