generated from dbt-labs/dbt-oss-template
-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Behavior Flag Framework #183
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
06684bf
add behavior flag framework
mikealfare 629f4ce
support older versions of python
mikealfare fd584a5
add sample flag for even
mikealfare 8aff7bf
changelog
mikealfare 2d7655a
add no_warn option for behavior flags
mikealfare 60a004a
Merge branch 'main' into behavior-flags
mikealfare 267061b
bump version for downstream testing
mikealfare 8fc6485
update user_flags to user_overrides
mikealfare 6adff8c
update Behavior from SimpleNamespace to a custom class to support typing
mikealfare b9ad7c2
move flag initialization into rendered flag, adopt Rendered naming co…
mikealfare 8e919f5
fix the default source test
mikealfare 12c8cb0
fix the event code; update docs
mikealfare 90ddfb3
update docs
mikealfare 591e5c1
update docs
mikealfare 841a0b8
use the correct exception in Behavior
mikealfare 9eca0d2
move event_catcher fixture to be reusable
mikealfare 9f07b2b
add a unit test for raising the correct exception
mikealfare File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
kind: Features | ||
body: Add Behavior Flag Framework | ||
time: 2024-08-08T19:49:33.738569-04:00 | ||
custom: | ||
Author: mikealfare | ||
Issue: "178" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
version = "1.7.0" | ||
version = "1.8.0a1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import inspect | ||
from typing import Any, Dict, List, TypedDict | ||
|
||
try: | ||
from typing import NotRequired | ||
except ImportError: | ||
# NotRequired was introduced in Python 3.11 | ||
# This is the suggested way to implement a TypedDict with optional arguments | ||
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 | ||
|
||
|
||
class BehaviorFlag(TypedDict): | ||
""" | ||
Configuration used to create a BehaviorFlagRendered instance | ||
|
||
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 | ||
docs_url: the url to the relevant docs on docs.getdbt.com | ||
""" | ||
|
||
name: str | ||
default: bool | ||
source: NotRequired[str] | ||
deprecation_version: NotRequired[str] | ||
deprecation_message: NotRequired[str] | ||
docs_url: NotRequired[str] | ||
|
||
|
||
class BehaviorFlagRendered: | ||
""" | ||
A rendered behavior flag that gets used throughout dbt packages | ||
|
||
Args: | ||
flag: the configuration for the behavior flag | ||
user_overrides: a set of user settings, one of which may be an override on this behavior flag | ||
""" | ||
|
||
def __init__(self, flag: BehaviorFlag, user_overrides: Dict[str, Any]) -> None: | ||
self.name = flag["name"] | ||
self.setting = user_overrides.get(flag["name"], flag["default"]) | ||
self.deprecation_event = self._deprecation_event(flag) | ||
|
||
@property | ||
def setting(self) -> bool: | ||
if self._setting is False: | ||
fire_event(self.deprecation_event) | ||
return self._setting | ||
|
||
@setting.setter | ||
def setting(self, value: bool) -> None: | ||
self._setting = value | ||
|
||
@property | ||
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: | ||
""" | ||
If the maintainer did not provide a source, default to the module that called this class. | ||
For adapters, this will likely be `dbt.adapters.<foo>.impl` for `dbt-foo`. | ||
""" | ||
for frame in inspect.stack(): | ||
if module := inspect.getmodule(frame[0]): | ||
if module.__name__ != __name__: | ||
return module.__name__ | ||
return "Unknown" | ||
|
||
def __bool__(self) -> bool: | ||
return self.setting | ||
|
||
|
||
class Behavior: | ||
""" | ||
A collection of behavior flags | ||
|
||
This is effectively a dictionary that supports dot notation for easy reference, e.g.: | ||
```python | ||
if adapter.behavior.my_flag: | ||
... | ||
|
||
if adapter.behavior.my_flag.no_warn: # this will not fire the deprecation event | ||
... | ||
``` | ||
```jinja | ||
{% if adapter.behavior.my_flag %} | ||
... | ||
{% endif %} | ||
|
||
{% if adapter.behavior.my_flag.no_warn %} {# this will not fire the deprecation event #} | ||
... | ||
{% endif %} | ||
``` | ||
|
||
Args: | ||
flags: a list of configurations, one for each behavior flag | ||
user_overrides: a set of user settings, which may include overrides on one or more of the behavior flags | ||
""" | ||
|
||
_flags: List[BehaviorFlagRendered] | ||
|
||
def __init__(self, flags: List[BehaviorFlag], user_overrides: Dict[str, Any]) -> None: | ||
self._flags = [BehaviorFlagRendered(flag, user_overrides) for flag in flags] | ||
|
||
def __getattr__(self, name: str) -> BehaviorFlagRendered: | ||
for flag in self._flags: | ||
if flag.name == name: | ||
return flag | ||
raise CompilationError(f"The flag {name} has not be registered.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -127,9 +127,10 @@ exclude = [ | |
"dbt_common/events/types_pb2.py", | ||
"venv", | ||
".venv", | ||
"env*" | ||
"env*", | ||
".hatch/*", | ||
] | ||
per-file-ignores = ["*/__init__.py: F401"] | ||
per-file-ignores = ["*/__init__.py: F401", "*/conftest.py: F401"] | ||
docstring-convention = "google" | ||
|
||
[tool.mypy] | ||
|
@@ -140,6 +141,7 @@ show_error_codes = true | |
disable_error_code = "attr-defined" # TODO: revisit once other mypy errors resolved | ||
disallow_untyped_defs = false # TODO: add type annotations everywhere | ||
warn_redundant_casts = true | ||
ignore_missing_imports = true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
exclude = [ | ||
"dbt_common/events/types_pb2.py", | ||
"env*", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from tests.unit.utils import event_catcher |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pytest
fixtures get registered by importing them intoconftest.py
. They do not need to be used in that file.