Skip to content

Commit

Permalink
Merge branch 'main' into cl/print_event
Browse files Browse the repository at this point in the history
  • Loading branch information
ChenyuLInx authored May 15, 2024
2 parents c8db500 + 3b61b6f commit 21f3abf
Show file tree
Hide file tree
Showing 12 changed files with 69 additions and 17 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/Features-20240514-162052.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: Support adding callbacks to the event manager
time: 2024-05-14T16:20:52.120336-07:00
custom:
Author: QMalcolm
Issue: "131"
5 changes: 4 additions & 1 deletion dbt_common/events/base_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from google.protobuf.json_format import ParseDict, MessageToDict, MessageToJson
from google.protobuf.message import Message
from dbt_common.events.helpers import get_json_string_utcnow
from typing import Optional
from typing import Callable, Optional

from dbt_common.invocation import get_invocation_id

Expand Down Expand Up @@ -128,6 +128,9 @@ class EventMsg(Protocol):
data: Message


TCallback = Callable[[EventMsg], None]


def msg_from_base_event(event: BaseEvent, level: Optional[EventLevel] = None):
msg_class_name = f"{type(event).__name__}Msg"
msg_cls = getattr(event.PROTO_TYPES_MODULE, msg_class_name)
Expand Down
14 changes: 10 additions & 4 deletions dbt_common/events/event_manager.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import os
import traceback
from typing import Callable, List, Optional, Protocol, Tuple
from typing import List, Optional, Protocol, Tuple

from dbt_common.events.base_types import BaseEvent, EventLevel, msg_from_base_event, EventMsg
from dbt_common.events.base_types import BaseEvent, EventLevel, msg_from_base_event, TCallback
from dbt_common.events.logger import LoggerConfig, _Logger, _TextLogger, _JsonLogger, LineFormat


class EventManager:
def __init__(self) -> None:
self.loggers: List[_Logger] = []
self.callbacks: List[Callable[[EventMsg], None]] = []
self.callbacks: List[TCallback] = []

def fire_event(self, e: BaseEvent, level: Optional[EventLevel] = None) -> None:
msg = msg_from_base_event(e, level=level)
Expand Down Expand Up @@ -37,13 +37,16 @@ def add_logger(self, config: LoggerConfig) -> None:
)
self.loggers.append(logger)

def add_callback(self, callback: TCallback) -> None:
self.callbacks.append(callback)

def flush(self) -> None:
for logger in self.loggers:
logger.flush()


class IEventManager(Protocol):
callbacks: List[Callable[[EventMsg], None]]
callbacks: List[TCallback]
loggers: List[_Logger]

def fire_event(self, e: BaseEvent, level: Optional[EventLevel] = None) -> None:
Expand All @@ -52,6 +55,9 @@ def fire_event(self, e: BaseEvent, level: Optional[EventLevel] = None) -> None:
def add_logger(self, config: LoggerConfig) -> None:
...

def add_callback(self, callback: TCallback) -> None:
...


class TestEventManager(IEventManager):
__test__ = False
Expand Down
6 changes: 6 additions & 0 deletions dbt_common/events/event_manager_client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Since dbt-rpc does not do its own log setup, and since some events can
# currently fire before logs can be configured by setup_event_logger(), we
# create a default configuration with default settings and no file output.
from dbt_common.events.base_types import TCallback
from dbt_common.events.event_manager import IEventManager, EventManager

_EVENT_MANAGER: IEventManager = EventManager()
Expand All @@ -16,6 +17,11 @@ def add_logger_to_manager(logger) -> None:
_EVENT_MANAGER.add_logger(logger)


def add_callback_to_manager(callback: TCallback) -> None:
global _EVENT_MANAGER
_EVENT_MANAGER.add_callback(callback)


def ctx_set_event_manager(event_manager: IEventManager) -> None:
global _EVENT_MANAGER
_EVENT_MANAGER = event_manager
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ lint = [
]
test = [
"pytest>=7.3,<8.0",
"pytest-mock",
"pytest-xdist>=3.2,<4.0",
"pytest-cov>=4.1,<5.0",
"hypothesis>=6.87,<7.0",
Expand Down
Empty file added tests/__init__.py
Empty file.
Empty file added tests/unit/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions tests/unit/test_event_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from dbt_common.events.event_manager import EventManager
from tests.unit.utils import EventCatcher


class TestEventManager:
def test_add_callback(self) -> None:
event_manager = EventManager()
assert len(event_manager.callbacks) == 0

event_manager.add_callback(EventCatcher().catch)
assert len(event_manager.callbacks) == 1
15 changes: 15 additions & 0 deletions tests/unit/test_event_manager_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from pytest_mock import MockerFixture

from dbt_common.events.event_manager import EventManager
from dbt_common.events.event_manager_client import add_callback_to_manager, get_event_manager
from tests.unit.utils import EventCatcher


def test_add_callback_to_manager(mocker: MockerFixture) -> None:
# mock out the global event manager so the callback doesn't get added to all other tests
mocker.patch("dbt_common.events.event_manager_client._EVENT_MANAGER", EventManager())
manager = get_event_manager()
assert len(manager.callbacks) == 0

add_callback_to_manager(EventCatcher().catch)
assert len(manager.callbacks) == 1
2 changes: 1 addition & 1 deletion tests/unit/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def get_all_subclasses(cls):
InfoLevel,
ErrorLevel,
DynamicLevel,
] and not subclass.__module__.startswith("test_"):
] and not subclass.__module__.startswith("tests."):
all_subclasses.append(subclass)
all_subclasses.extend(get_all_subclasses(subclass))
return set(all_subclasses)
Expand Down
14 changes: 3 additions & 11 deletions tests/unit/test_functions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import pytest

from dataclasses import dataclass, field
from dbt_common.events import functions
from dbt_common.events.base_types import EventLevel, EventMsg, WarnLevel
from dbt_common.events.base_types import EventLevel, WarnLevel
from dbt_common.events.event_manager import EventManager
from dbt_common.events.event_manager_client import ctx_set_event_manager
from dbt_common.exceptions import EventCompilationError
from dbt_common.helper_types import WarnErrorOptions
from typing import List, Set
from tests.unit.utils import EventCatcher
from typing import Set


# Re-implementing `Note` event as a warn event for
Expand All @@ -20,14 +20,6 @@ def message(self) -> str:
return self.msg


@dataclass
class EventCatcher:
caught_events: List[EventMsg] = field(default_factory=list)

def catch(self, event: EventMsg) -> None:
self.caught_events.append(event)


@pytest.fixture(scope="function")
def event_catcher() -> EventCatcher:
return EventCatcher()
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from dataclasses import dataclass, field
from typing import List

from dbt_common.events.base_types import EventMsg


@dataclass
class EventCatcher:
caught_events: List[EventMsg] = field(default_factory=list)

def catch(self, event: EventMsg) -> None:
self.caught_events.append(event)

0 comments on commit 21f3abf

Please sign in to comment.