From 821d65b884051200a1b3de0368829181b51ba2e9 Mon Sep 17 00:00:00 2001 From: Nathaniel May Date: Mon, 25 Oct 2021 14:41:03 -0400 Subject: [PATCH] model ADTs with dataclasses and union types --- core/dbt/events/events.py | 54 +++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/core/dbt/events/events.py b/core/dbt/events/events.py index 016d59cf012..78171cae990 100644 --- a/core/dbt/events/events.py +++ b/core/dbt/events/events.py @@ -1,26 +1,42 @@ +from dataclasses import dataclass +from typing import NoReturn, Union -class Singleton: - __instance = None - @staticmethod - def getInstance(): - """ Static access method. """ - if Singleton.__instance == None: - Singleton() - return Singleton.__instance - def __init__(self): - """ Virtually private constructor. """ - if Singleton.__instance != None: - raise Exception("This class is a singleton!") - else: - Singleton.__instance = self +# common trick for getting mypy to do exhaustiveness checks +# will come up with something like `"assert_never" has incompatible type` +# if something is missing. +def assert_never(x: NoReturn) -> NoReturn: + raise AssertionError("Unhandled type: {}".format(type(x).__name__)) -# All classes that inherit from this one should be defined in this file. -class BaseEvent(): - pass +# TODO dummy class +@dataclass(frozen=True) +class OK: + result: int -class StartParse(BaseEvent): - pass +# TODO dummy class +@dataclass(frozen=True) +class Failure: + msg: str + + +# using a union instead of inheritance means that this set cannot +# be extended outside this file, and thus mypy can do exhaustiveness +# checks for us. +Event = Union[OK, Failure] + + +# function that translates any instance of the above event types +# into its human-readable message. +# +# This could instead be implemented as a method on an ABC for all +# above classes, but this at least puts all that logic in one place. +def humanMsg(r: Event) -> str: + if isinstance(r, OK): + return str(r.result) + elif isinstance(r, Failure): + return "Failure: " + r.msg + else: + assert_never(r)