From f6088db25b4a386db49dfda5de613d1e70bb2445 Mon Sep 17 00:00:00 2001 From: devmessias Date: Mon, 14 Oct 2024 17:09:19 -0300 Subject: [PATCH 1/2] doc: temp change to illustrate a point --- core/dbt/parser/unit_tests.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/dbt/parser/unit_tests.py b/core/dbt/parser/unit_tests.py index 0e60c90274b..a29045df6d7 100644 --- a/core/dbt/parser/unit_tests.py +++ b/core/dbt/parser/unit_tests.py @@ -104,6 +104,15 @@ def parse_unit_test_case(self, test_case: UnitTestDefinition): self.manifest, test_case.package_name, ) + + # just to illustrate the issue in #..., but this change is obviously not + # the correct solution. I’ll wait for a discussion before writing any more + # advanced code. + + if "var" not in ctx: + ctx["var"] = lambda var_name, default =None: default + if "env_var" not in ctx: + ctx["env_var"] = lambda var_name, default=None: default get_rendered(unit_test_node.raw_code, ctx, unit_test_node, capture_macros=True) # unit_test_node now has a populated refs/sources From 7def903dec947af459e775107386be07352824ae Mon Sep 17 00:00:00 2001 From: devmessias Date: Thu, 17 Oct 2024 13:52:47 -0300 Subject: [PATCH 2/2] fix: create var and env_var exposure --- core/dbt/context/providers.py | 61 ++++++++++++++++++++++++++++++++++- core/dbt/parser/unit_tests.py | 10 +----- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/core/dbt/context/providers.py b/core/dbt/context/providers.py index dfc8c9bb40b..0c9d04308d6 100644 --- a/core/dbt/context/providers.py +++ b/core/dbt/context/providers.py @@ -257,7 +257,9 @@ def resolve_event_time_filter(self, target: ManifestNode) -> Optional[EventTimeF return event_time_filter @abc.abstractmethod - def __call__(self, *args: str) -> Union[str, RelationProxy, MetricReference]: + def __call__( + self, *args: str + ) -> Optional[Union[str, int, float, RelationProxy, MetricReference]]: pass @@ -1788,6 +1790,61 @@ def __call__(self, *args, **kwargs) -> str: return "" +class ExposureVarResolver(BaseResolver): + def __call__(self, *args) -> Any: # ?? -> Any?? + n_args = len(args) + if n_args == 0 or n_args > 2: + raise RefArgsError(node=self.model, args=args) + var = args[0] + default = None if n_args == 1 else args[1] + # context is None using the same decision at + # generate_runtime_unit_test_context + return UnitTestVar(context={}, config=self.config, node=self.model)(var, default) + + +# Should we create a new copy of the `envvar` method, similar to what was done for +# `TextContext` and `ProviderContext`? +class ExposureEnvVarResolver(BaseResolver): + def __call__(self, *args) -> Optional[Union[int, float, str]]: + n_args = len(args) + if n_args == 0 or n_args > 2: + raise RefArgsError(node=self.model, args=args) + var = args[0] + default = None if n_args == 1 else args[1] + + return_value = None + if var.startswith(SECRET_ENV_PREFIX): + raise SecretEnvVarLocationError(var) + + env = get_invocation_context().env + if var in env: + return_value = env[var] + elif default is not None: + return_value = default + + if return_value is not None: + # Save the env_var value in the manifest and the var name in the source_file + if self.model: + # If the environment variable is set from a default, store a string indicating + # that so we can skip partial parsing. Otherwise the file will be scheduled for + # reparsing. If the default changes, the file will have been updated and therefore + # will be scheduled for reparsing anyways. + self.manifest.env_vars[var] = ( + return_value if var in env else DEFAULT_ENV_PLACEHOLDER + ) + # the "model" should only be test nodes, but just in case, check + # TODO CT-211 + if self.model.resource_type == NodeType.Test and self.model.file_key_name: # type: ignore[union-attr] # noqa + source_file = self.manifest.files[self.model.file_id] + # TODO CT-211 + (yaml_key, name) = self.model.file_key_name.split(".") # type: ignore[union-attr] # noqa + # TODO CT-211 + source_file.add_env_var(var, yaml_key, name) # type: ignore[union-attr] + return return_value + else: + raise EnvVarMissingError(var) + + class ExposureSourceResolver(BaseResolver): def __call__(self, *args) -> str: if len(args) != 2: @@ -1830,6 +1887,8 @@ def generate_parse_exposure( project, manifest, ), + "var": ExposureVarResolver(None, exposure, project, manifest), + "env_var": ExposureEnvVarResolver(None, exposure, project, manifest), } diff --git a/core/dbt/parser/unit_tests.py b/core/dbt/parser/unit_tests.py index a29045df6d7..659fc7ac2ad 100644 --- a/core/dbt/parser/unit_tests.py +++ b/core/dbt/parser/unit_tests.py @@ -100,19 +100,11 @@ def parse_unit_test_case(self, test_case: UnitTestDefinition): ctx = generate_parse_exposure( unit_test_node, # type: ignore - self.root_project, + self.root_project, # config self.manifest, test_case.package_name, ) - # just to illustrate the issue in #..., but this change is obviously not - # the correct solution. I’ll wait for a discussion before writing any more - # advanced code. - - if "var" not in ctx: - ctx["var"] = lambda var_name, default =None: default - if "env_var" not in ctx: - ctx["env_var"] = lambda var_name, default=None: default get_rendered(unit_test_node.raw_code, ctx, unit_test_node, capture_macros=True) # unit_test_node now has a populated refs/sources