diff --git a/dbt_common/behavior_flags.py b/dbt_common/behavior_flags.py index a647ed7..a2eb097 100644 --- a/dbt_common/behavior_flags.py +++ b/dbt_common/behavior_flags.py @@ -9,8 +9,8 @@ from typing import Optional as NotRequired from dbt_common.events.functions import fire_event -from dbt_common.events.types import BehaviorDeprecationEvent -from dbt_common.exceptions import CompilationError +from dbt_common.events.types import BehaviorChangeEvent +from dbt_common.exceptions import CompilationError, DbtInternalError class BehaviorFlag(TypedDict): @@ -20,16 +20,20 @@ class BehaviorFlag(TypedDict): Args: name: the name of the behavior flag default: default setting, starts as False, becomes True after a bake-in period - deprecation_version: the version when the default will change to True - deprecation_message: an additional message to send when the flag evaluates to False + description: an additional message to send when the flag evaluates to False docs_url: the url to the relevant docs on docs.getdbt.com + + *Note*: + While `description` and `docs_url` are both listed as `NotRequired`, at least one of them is required. + This is validated when the flag is rendered in `BehaviorFlagRendered` below. + The goal of this restriction is to provide the end user with context so they can make an informed decision + about if, and when, to enable the behavior flag. """ name: str default: bool source: NotRequired[str] - deprecation_version: NotRequired[str] - deprecation_message: NotRequired[str] + description: NotRequired[str] docs_url: NotRequired[str] @@ -43,14 +47,33 @@ class BehaviorFlagRendered: """ def __init__(self, flag: BehaviorFlag, user_overrides: Dict[str, Any]) -> None: + self._validate(flag) + self.name = flag["name"] self.setting = user_overrides.get(flag["name"], flag["default"]) - self.deprecation_event = self._deprecation_event(flag) + + default_description = ( + f"""The behavior controlled by `{flag["name"]}` is currently turned off.\n""" + ) + default_docs_url = "https://docs.getdbt.com/reference/global-configs/behavior-changes" + self._behavior_change_event = BehaviorChangeEvent( + flag_name=flag["name"], + flag_source=flag.get("source", self._default_source()), + description=flag.get("description", default_description), + docs_url=flag.get("docs_url", default_docs_url), + ) + + @staticmethod + def _validate(flag: BehaviorFlag) -> None: + if flag.get("description") is None and flag.get("docs_url") is None: + raise DbtInternalError( + "Behavior change flags require at least one of `description` and `docs_url`." + ) @property def setting(self) -> bool: if self._setting is False: - fire_event(self.deprecation_event) + fire_event(self._behavior_change_event) return self._setting @setting.setter @@ -61,15 +84,6 @@ def setting(self, value: bool) -> None: def no_warn(self) -> bool: return self._setting - def _deprecation_event(self, flag: BehaviorFlag) -> BehaviorDeprecationEvent: - return BehaviorDeprecationEvent( - flag_name=flag["name"], - flag_source=flag.get("source", self._default_source()), - deprecation_version=flag.get("deprecation_version"), - deprecation_message=flag.get("deprecation_message"), - docs_url=flag.get("docs_url"), - ) - @staticmethod def _default_source() -> str: """ @@ -95,7 +109,7 @@ class Behavior: if adapter.behavior.my_flag: ... - if adapter.behavior.my_flag.no_warn: # this will not fire the deprecation event + if adapter.behavior.my_flag.no_warn: # this will not fire the behavior change event ... ``` ```jinja @@ -103,7 +117,7 @@ class Behavior: ... {% endif %} - {% if adapter.behavior.my_flag.no_warn %} {# this will not fire the deprecation event #} + {% if adapter.behavior.my_flag.no_warn %} {# this will not fire the behavior change event #} ... {% endif %} ``` diff --git a/dbt_common/events/types.proto b/dbt_common/events/types.proto index d72d6b2..3826a0f 100644 --- a/dbt_common/events/types.proto +++ b/dbt_common/events/types.proto @@ -26,17 +26,16 @@ message GenericMessage { // D - Deprecations // D018 -message BehaviorDeprecationEvent { +message BehaviorChangeEvent { string flag_name = 1; string flag_source = 2; - string deprecation_version = 3; - string deprecation_message = 4; - string docs_url = 5; + string description = 3; + string docs_url = 4; } -message BehaviorDeprecationEventMsg { +message BehaviorChangeEventMsg { EventInfo info = 1; - BehaviorDeprecationEvent data = 2; + BehaviorChangeEvent data = 2; } // M - Deps generation diff --git a/dbt_common/events/types.py b/dbt_common/events/types.py index 02fc3ee..e098c0c 100644 --- a/dbt_common/events/types.py +++ b/dbt_common/events/types.py @@ -1,5 +1,3 @@ -from typing import Optional - from dbt_common.events.base_types import ( DebugLevel, InfoLevel, @@ -38,33 +36,16 @@ # ======================================================= -class BehaviorDeprecationEvent(WarnLevel): - flag_name: str - flag_source: str - deprecation_version: Optional[str] - deprecation_message: Optional[str] - docs_url: Optional[str] - +class BehaviorChangeEvent(WarnLevel): def code(self) -> str: return "D018" def message(self) -> str: - msg = f"The legacy behavior controlled by `{self.flag_name}` is deprecated.\n" - - if self.deprecation_version: - msg = ( - f"The legacy behavior is expected to be retired in `{self.deprecation_version}`.\n" - ) - - msg += f"The new behavior can be turned on by setting `flags.{self.flag_name}` to `True` in `dbt_project.yml`.\n" - - if self.deprecation_message: - msg += f"{self.deprecation_message}.\n" - - docs_url = self.docs_url or f"https://docs.getdbt.com/search?q={self.flag_name}" - msg += f"Visit {docs_url} for more information." - - return warning_tag(msg) + return warning_tag( + f"{self.description}\n" + f"You may opt into the new behavior sooner by setting `flags.{self.flag_name}` to `True` in `dbt_project.yml`.\n" + f"Visit {self.docs_url} for more information." + ) # ======================================================= diff --git a/dbt_common/events/types_pb2.py b/dbt_common/events/types_pb2.py index 6b3afc5..6574462 100644 --- a/dbt_common/events/types_pb2.py +++ b/dbt_common/events/types_pb2.py @@ -15,7 +15,7 @@ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btypes.proto\x12\x0bproto_types\x1a\x1fgoogle/protobuf/timestamp.proto\"\x91\x02\n\tEventInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0b\n\x03msg\x18\x03 \x01(\t\x12\r\n\x05level\x18\x04 \x01(\t\x12\x15\n\rinvocation_id\x18\x05 \x01(\t\x12\x0b\n\x03pid\x18\x06 \x01(\x05\x12\x0e\n\x06thread\x18\x07 \x01(\t\x12&\n\x02ts\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x30\n\x05\x65xtra\x18\t \x03(\x0b\x32!.proto_types.EventInfo.ExtraEntry\x12\x10\n\x08\x63\x61tegory\x18\n \x01(\t\x1a,\n\nExtraEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"6\n\x0eGenericMessage\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\"\x8e\x01\n\x18\x42\x65haviorDeprecationEvent\x12\x11\n\tflag_name\x18\x01 \x01(\t\x12\x13\n\x0b\x66lag_source\x18\x02 \x01(\t\x12\x1b\n\x13\x64\x65precation_version\x18\x03 \x01(\t\x12\x1b\n\x13\x64\x65precation_message\x18\x04 \x01(\t\x12\x10\n\x08\x64ocs_url\x18\x05 \x01(\t\"x\n\x1b\x42\x65haviorDeprecationEventMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12\x33\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32%.proto_types.BehaviorDeprecationEvent\"1\n\x11RetryExternalCall\x12\x0f\n\x07\x61ttempt\x18\x01 \x01(\x05\x12\x0b\n\x03max\x18\x02 \x01(\x05\"j\n\x14RetryExternalCallMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12,\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x1e.proto_types.RetryExternalCall\"#\n\x14RecordRetryException\x12\x0b\n\x03\x65xc\x18\x01 \x01(\t\"p\n\x17RecordRetryExceptionMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12/\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32!.proto_types.RecordRetryException\"@\n\x13SystemCouldNotWrite\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x0b\n\x03\x65xc\x18\x03 \x01(\t\"n\n\x16SystemCouldNotWriteMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12.\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32 .proto_types.SystemCouldNotWrite\"!\n\x12SystemExecutingCmd\x12\x0b\n\x03\x63md\x18\x01 \x03(\t\"l\n\x15SystemExecutingCmdMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12-\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x1f.proto_types.SystemExecutingCmd\"\x1c\n\x0cSystemStdOut\x12\x0c\n\x04\x62msg\x18\x01 \x01(\t\"`\n\x0fSystemStdOutMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12\'\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x19.proto_types.SystemStdOut\"\x1c\n\x0cSystemStdErr\x12\x0c\n\x04\x62msg\x18\x01 \x01(\t\"`\n\x0fSystemStdErrMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12\'\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x19.proto_types.SystemStdErr\",\n\x16SystemReportReturnCode\x12\x12\n\nreturncode\x18\x01 \x01(\x05\"t\n\x19SystemReportReturnCodeMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12\x31\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32#.proto_types.SystemReportReturnCode\"\x19\n\nFormatting\x12\x0b\n\x03msg\x18\x01 \x01(\t\"\\\n\rFormattingMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12%\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x17.proto_types.Formatting\"\x13\n\x04Note\x12\x0b\n\x03msg\x18\x01 \x01(\t\"P\n\x07NoteMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12\x1f\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x11.proto_types.Note\"\x19\n\nPrintEvent\x12\x0b\n\x03msg\x18\x01 \x01(\t\"\\\n\rPrintEventMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12%\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x17.proto_types.PrintEventb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0btypes.proto\x12\x0bproto_types\x1a\x1fgoogle/protobuf/timestamp.proto\"\x91\x02\n\tEventInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0b\n\x03msg\x18\x03 \x01(\t\x12\r\n\x05level\x18\x04 \x01(\t\x12\x15\n\rinvocation_id\x18\x05 \x01(\t\x12\x0b\n\x03pid\x18\x06 \x01(\x05\x12\x0e\n\x06thread\x18\x07 \x01(\t\x12&\n\x02ts\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x30\n\x05\x65xtra\x18\t \x03(\x0b\x32!.proto_types.EventInfo.ExtraEntry\x12\x10\n\x08\x63\x61tegory\x18\n \x01(\t\x1a,\n\nExtraEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"6\n\x0eGenericMessage\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\"d\n\x13\x42\x65haviorChangeEvent\x12\x11\n\tflag_name\x18\x01 \x01(\t\x12\x13\n\x0b\x66lag_source\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x10\n\x08\x64ocs_url\x18\x04 \x01(\t\"n\n\x16\x42\x65haviorChangeEventMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12.\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32 .proto_types.BehaviorChangeEvent\"1\n\x11RetryExternalCall\x12\x0f\n\x07\x61ttempt\x18\x01 \x01(\x05\x12\x0b\n\x03max\x18\x02 \x01(\x05\"j\n\x14RetryExternalCallMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12,\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x1e.proto_types.RetryExternalCall\"#\n\x14RecordRetryException\x12\x0b\n\x03\x65xc\x18\x01 \x01(\t\"p\n\x17RecordRetryExceptionMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12/\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32!.proto_types.RecordRetryException\"@\n\x13SystemCouldNotWrite\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x0b\n\x03\x65xc\x18\x03 \x01(\t\"n\n\x16SystemCouldNotWriteMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12.\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32 .proto_types.SystemCouldNotWrite\"!\n\x12SystemExecutingCmd\x12\x0b\n\x03\x63md\x18\x01 \x03(\t\"l\n\x15SystemExecutingCmdMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12-\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x1f.proto_types.SystemExecutingCmd\"\x1c\n\x0cSystemStdOut\x12\x0c\n\x04\x62msg\x18\x01 \x01(\t\"`\n\x0fSystemStdOutMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12\'\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x19.proto_types.SystemStdOut\"\x1c\n\x0cSystemStdErr\x12\x0c\n\x04\x62msg\x18\x01 \x01(\t\"`\n\x0fSystemStdErrMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12\'\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x19.proto_types.SystemStdErr\",\n\x16SystemReportReturnCode\x12\x12\n\nreturncode\x18\x01 \x01(\x05\"t\n\x19SystemReportReturnCodeMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12\x31\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32#.proto_types.SystemReportReturnCode\"\x19\n\nFormatting\x12\x0b\n\x03msg\x18\x01 \x01(\t\"\\\n\rFormattingMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12%\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x17.proto_types.Formatting\"\x13\n\x04Note\x12\x0b\n\x03msg\x18\x01 \x01(\t\"P\n\x07NoteMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12\x1f\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x11.proto_types.Note\"\x19\n\nPrintEvent\x12\x0b\n\x03msg\x18\x01 \x01(\t\"\\\n\rPrintEventMsg\x12$\n\x04info\x18\x01 \x01(\x0b\x32\x16.proto_types.EventInfo\x12%\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x17.proto_types.PrintEventb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -30,48 +30,48 @@ _globals['_EVENTINFO_EXTRAENTRY']._serialized_end=335 _globals['_GENERICMESSAGE']._serialized_start=337 _globals['_GENERICMESSAGE']._serialized_end=391 - _globals['_BEHAVIORDEPRECATIONEVENT']._serialized_start=394 - _globals['_BEHAVIORDEPRECATIONEVENT']._serialized_end=536 - _globals['_BEHAVIORDEPRECATIONEVENTMSG']._serialized_start=538 - _globals['_BEHAVIORDEPRECATIONEVENTMSG']._serialized_end=658 - _globals['_RETRYEXTERNALCALL']._serialized_start=660 - _globals['_RETRYEXTERNALCALL']._serialized_end=709 - _globals['_RETRYEXTERNALCALLMSG']._serialized_start=711 - _globals['_RETRYEXTERNALCALLMSG']._serialized_end=817 - _globals['_RECORDRETRYEXCEPTION']._serialized_start=819 - _globals['_RECORDRETRYEXCEPTION']._serialized_end=854 - _globals['_RECORDRETRYEXCEPTIONMSG']._serialized_start=856 - _globals['_RECORDRETRYEXCEPTIONMSG']._serialized_end=968 - _globals['_SYSTEMCOULDNOTWRITE']._serialized_start=970 - _globals['_SYSTEMCOULDNOTWRITE']._serialized_end=1034 - _globals['_SYSTEMCOULDNOTWRITEMSG']._serialized_start=1036 - _globals['_SYSTEMCOULDNOTWRITEMSG']._serialized_end=1146 - _globals['_SYSTEMEXECUTINGCMD']._serialized_start=1148 - _globals['_SYSTEMEXECUTINGCMD']._serialized_end=1181 - _globals['_SYSTEMEXECUTINGCMDMSG']._serialized_start=1183 - _globals['_SYSTEMEXECUTINGCMDMSG']._serialized_end=1291 - _globals['_SYSTEMSTDOUT']._serialized_start=1293 - _globals['_SYSTEMSTDOUT']._serialized_end=1321 - _globals['_SYSTEMSTDOUTMSG']._serialized_start=1323 - _globals['_SYSTEMSTDOUTMSG']._serialized_end=1419 - _globals['_SYSTEMSTDERR']._serialized_start=1421 - _globals['_SYSTEMSTDERR']._serialized_end=1449 - _globals['_SYSTEMSTDERRMSG']._serialized_start=1451 - _globals['_SYSTEMSTDERRMSG']._serialized_end=1547 - _globals['_SYSTEMREPORTRETURNCODE']._serialized_start=1549 - _globals['_SYSTEMREPORTRETURNCODE']._serialized_end=1593 - _globals['_SYSTEMREPORTRETURNCODEMSG']._serialized_start=1595 - _globals['_SYSTEMREPORTRETURNCODEMSG']._serialized_end=1711 - _globals['_FORMATTING']._serialized_start=1713 - _globals['_FORMATTING']._serialized_end=1738 - _globals['_FORMATTINGMSG']._serialized_start=1740 - _globals['_FORMATTINGMSG']._serialized_end=1832 - _globals['_NOTE']._serialized_start=1834 - _globals['_NOTE']._serialized_end=1853 - _globals['_NOTEMSG']._serialized_start=1855 - _globals['_NOTEMSG']._serialized_end=1935 - _globals['_PRINTEVENT']._serialized_start=1937 - _globals['_PRINTEVENT']._serialized_end=1962 - _globals['_PRINTEVENTMSG']._serialized_start=1964 - _globals['_PRINTEVENTMSG']._serialized_end=2056 + _globals['_BEHAVIORCHANGEEVENT']._serialized_start=393 + _globals['_BEHAVIORCHANGEEVENT']._serialized_end=493 + _globals['_BEHAVIORCHANGEEVENTMSG']._serialized_start=495 + _globals['_BEHAVIORCHANGEEVENTMSG']._serialized_end=605 + _globals['_RETRYEXTERNALCALL']._serialized_start=607 + _globals['_RETRYEXTERNALCALL']._serialized_end=656 + _globals['_RETRYEXTERNALCALLMSG']._serialized_start=658 + _globals['_RETRYEXTERNALCALLMSG']._serialized_end=764 + _globals['_RECORDRETRYEXCEPTION']._serialized_start=766 + _globals['_RECORDRETRYEXCEPTION']._serialized_end=801 + _globals['_RECORDRETRYEXCEPTIONMSG']._serialized_start=803 + _globals['_RECORDRETRYEXCEPTIONMSG']._serialized_end=915 + _globals['_SYSTEMCOULDNOTWRITE']._serialized_start=917 + _globals['_SYSTEMCOULDNOTWRITE']._serialized_end=981 + _globals['_SYSTEMCOULDNOTWRITEMSG']._serialized_start=983 + _globals['_SYSTEMCOULDNOTWRITEMSG']._serialized_end=1093 + _globals['_SYSTEMEXECUTINGCMD']._serialized_start=1095 + _globals['_SYSTEMEXECUTINGCMD']._serialized_end=1128 + _globals['_SYSTEMEXECUTINGCMDMSG']._serialized_start=1130 + _globals['_SYSTEMEXECUTINGCMDMSG']._serialized_end=1238 + _globals['_SYSTEMSTDOUT']._serialized_start=1240 + _globals['_SYSTEMSTDOUT']._serialized_end=1268 + _globals['_SYSTEMSTDOUTMSG']._serialized_start=1270 + _globals['_SYSTEMSTDOUTMSG']._serialized_end=1366 + _globals['_SYSTEMSTDERR']._serialized_start=1368 + _globals['_SYSTEMSTDERR']._serialized_end=1396 + _globals['_SYSTEMSTDERRMSG']._serialized_start=1398 + _globals['_SYSTEMSTDERRMSG']._serialized_end=1494 + _globals['_SYSTEMREPORTRETURNCODE']._serialized_start=1496 + _globals['_SYSTEMREPORTRETURNCODE']._serialized_end=1540 + _globals['_SYSTEMREPORTRETURNCODEMSG']._serialized_start=1542 + _globals['_SYSTEMREPORTRETURNCODEMSG']._serialized_end=1658 + _globals['_FORMATTING']._serialized_start=1660 + _globals['_FORMATTING']._serialized_end=1685 + _globals['_FORMATTINGMSG']._serialized_start=1687 + _globals['_FORMATTINGMSG']._serialized_end=1779 + _globals['_NOTE']._serialized_start=1781 + _globals['_NOTE']._serialized_end=1800 + _globals['_NOTEMSG']._serialized_start=1802 + _globals['_NOTEMSG']._serialized_end=1882 + _globals['_PRINTEVENT']._serialized_start=1884 + _globals['_PRINTEVENT']._serialized_end=1909 + _globals['_PRINTEVENTMSG']._serialized_start=1911 + _globals['_PRINTEVENTMSG']._serialized_end=2003 # @@protoc_insertion_point(module_scope) diff --git a/tests/unit/test_behavior_flags.py b/tests/unit/test_behavior_flags.py index 73c550d..3c0ccce 100644 --- a/tests/unit/test_behavior_flags.py +++ b/tests/unit/test_behavior_flags.py @@ -1,15 +1,15 @@ import pytest from dbt_common.behavior_flags import Behavior -from dbt_common.exceptions.base import CompilationError +from dbt_common.exceptions.base import CompilationError, DbtInternalError from tests.unit.utils import EventCatcher def test_behavior_default() -> None: behavior = Behavior( [ - {"name": "default_false_flag", "default": False}, - {"name": "default_true_flag", "default": True}, + {"name": "default_false_flag", "default": False, "description": "This flag is false."}, + {"name": "default_true_flag", "default": True, "description": "This flag is true."}, ], {}, ) @@ -21,12 +21,28 @@ def test_behavior_default() -> None: def test_behavior_user_override() -> None: behavior = Behavior( [ - {"name": "flag_default_false", "default": False}, - {"name": "flag_default_false_override_false", "default": False}, - {"name": "flag_default_false_override_true", "default": False}, - {"name": "flag_default_true", "default": True}, - {"name": "flag_default_true_override_false", "default": True}, - {"name": "flag_default_true_override_true", "default": True}, + {"name": "flag_default_false", "default": False, "description": "This flag is false."}, + { + "name": "flag_default_false_override_false", + "default": False, + "description": "This flag is false.", + }, + { + "name": "flag_default_false_override_true", + "default": False, + "description": "This flag is true.", + }, + {"name": "flag_default_true", "default": True, "description": "This flag is true."}, + { + "name": "flag_default_true_override_false", + "default": True, + "description": "This flag is false.", + }, + { + "name": "flag_default_true_override_true", + "default": True, + "description": "This flag is true.", + }, ], { "flag_default_false_override_false": False, @@ -47,7 +63,11 @@ def test_behavior_user_override() -> None: def test_behavior_unregistered_flag_raises_correct_exception() -> None: behavior = Behavior( [ - {"name": "behavior_flag_exists", "default": False}, + { + "name": "behavior_flag_exists", + "default": False, + "description": "This flag is false.", + }, ], {}, ) @@ -60,8 +80,8 @@ def test_behavior_unregistered_flag_raises_correct_exception() -> None: def test_behavior_flag_can_be_used_as_conditional() -> None: behavior = Behavior( [ - {"name": "flag_false", "default": False}, - {"name": "flag_true", "default": True}, + {"name": "flag_false", "default": False, "description": "This flag is false."}, + {"name": "flag_true", "default": True, "description": "This flag is true."}, ], {}, ) @@ -70,11 +90,13 @@ def test_behavior_flag_can_be_used_as_conditional() -> None: assert True if behavior.flag_true else False -def test_behavior_flags_emit_deprecation_event_on_evaluation(event_catcher: EventCatcher) -> None: +def test_behavior_flags_emit_behavior_change_event_on_evaluation( + event_catcher: EventCatcher, +) -> None: behavior = Behavior( [ - {"name": "flag_false", "default": False}, - {"name": "flag_true", "default": True}, + {"name": "flag_false", "default": False, "description": "This flag is false."}, + {"name": "flag_true", "default": True, "description": "This flag is true."}, ], {}, ) @@ -90,21 +112,50 @@ def test_behavior_flags_emit_deprecation_event_on_evaluation(event_catcher: Even assert len(event_catcher.caught_events) == 1 -def test_behavior_flags_emit_correct_deprecation_event(event_catcher: EventCatcher) -> None: - behavior = Behavior([{"name": "flag_false", "default": False}], {}) +@pytest.mark.parametrize( + "flag,event", + [ + ( + {"name": "flag_false", "default": False, "description": "This flag is false."}, + { + "flag_name": "flag_false", + "flag_source": __name__, + "description": "This flag is false.", + "docs_url": "https://docs.getdbt.com/reference/global-configs/behavior-changes", + }, + ), + ( + {"name": "flag_false", "default": False, "docs_url": "https://docs.getdbt.com"}, + { + "flag_name": "flag_false", + "flag_source": __name__, + "description": "The behavior controlled by `flag_false` is currently turned off.\n", + "docs_url": "https://docs.getdbt.com", + }, + ), + ], +) +def test_behavior_flags_emit_correct_behavior_change_event( + event_catcher: EventCatcher, flag, event +) -> None: + behavior = Behavior([flag], {}) # trigger the evaluation if behavior.flag_false: pass msg = event_catcher.caught_events[0] - assert msg.info.name == "BehaviorDeprecationEvent" - assert msg.data.flag_name == "flag_false" - assert msg.data.flag_source == __name__ # defaults to the calling module + assert msg.info.name == "BehaviorChangeEvent" + assert msg.data.flag_name == event["flag_name"] + assert msg.data.flag_source == event["flag_source"] + assert msg.data.description == event["description"] + assert msg.data.docs_url == event["docs_url"] -def test_behavior_flags_no_deprecation_event_on_no_warn(event_catcher: EventCatcher) -> None: - behavior = Behavior([{"name": "flag_false", "default": False}], {}) +def test_behavior_flags_no_behavior_change_event_on_no_warn(event_catcher: EventCatcher) -> None: + behavior = Behavior( + [{"name": "flag_false", "default": False, "description": "This flag is false."}], {} + ) # trigger the evaluation with no_warn, no event should fire if behavior.flag_false.no_warn: @@ -115,3 +166,8 @@ def test_behavior_flags_no_deprecation_event_on_no_warn(event_catcher: EventCatc if behavior.flag_false: pass assert len(event_catcher.caught_events) == 1 + + +def test_behavior_flag_requires_description_or_docs_url(event_catcher: EventCatcher) -> None: + with pytest.raises(DbtInternalError): + Behavior([{"name": "flag_false", "default": False}], {}) diff --git a/tests/unit/test_events.py b/tests/unit/test_events.py index 9a9abc6..f89a2b2 100644 --- a/tests/unit/test_events.py +++ b/tests/unit/test_events.py @@ -62,7 +62,7 @@ class TestEventJSONSerialization: # N.B. Events instantiated here include the module prefix in order to # avoid having the entire list twice in the code. # D - Deprecations ====================== - types.BehaviorDeprecationEvent(flag_name="Do you have a flag?", flag_source="dbt_common"), + types.BehaviorChangeEvent(flag_name="Do you have a flag?", flag_source="dbt_common"), # M - Deps generation ====================== types.RetryExternalCall(attempt=0, max=0), types.RecordRetryException(exc=""),