Skip to content
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 project name to default search packages #4114

Merged

Conversation

JCZuurmond
Copy link
Contributor

@JCZuurmond JCZuurmond commented Oct 22, 2021

We prefer macros in the project over the ones in the namespace (package)

resolves #4106

Description

This changes will choose macros in the root project over the ones in the namespace.

Checklist

  • I have signed the CLA
  • I have run this code in development and it appears to resolve the stated issue
  • This PR includes tests, or tests are not required/relevant for this PR
  • I have updated the CHANGELOG.md and added information about my change

We prefer macros in the project over the ones in the namespace (package)
@cla-bot cla-bot bot added the cla:yes label Oct 22, 2021
@jtcohen6
Copy link
Contributor

Just going to close + re-open to re-trigger adapter integration tests, now that I've added the ok to test label

@jtcohen6 jtcohen6 closed this Oct 22, 2021
@jtcohen6 jtcohen6 reopened this Oct 22, 2021
@JCZuurmond
Copy link
Contributor Author

@jtcohen6 , I have troubles adding a test for this. I tried to add one to the test/unit/test_contexts.py module, but get stuck in what is mocked and what isn't.

Copy link
Contributor

@jtcohen6 jtcohen6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a unit test for dispatch over in dbt-redshift here, I think we could borrow some of that logic and pull it here. I'll edit this comment with a bit of code in a moment

This is tricky, but let's get the current tests passing first

core/dbt/context/providers.py Outdated Show resolved Hide resolved
@jtcohen6
Copy link
Contributor

Ok, the new issue in the unit tests: In dispatch: Could not find package 'X'

This error is raised by dispatch if we supply to search_order a package that does not have any macros defined. Which is not uncommon in unit tests, or in the real world. Let's think about a way to avoid raising that error.

@JCZuurmond
Copy link
Contributor Author

Is 't because no macros are found or because the package is not found?

            raise_compiler_error(
               f"Could not find package '{package_name}'"
            )

@jtcohen6
Copy link
Contributor

jtcohen6 commented Oct 22, 2021

If a package has no macros defined, the package doesn't appear in MacroResolver.packages:

# non-internal packages
for fnamespace in self.packages.values():
for macro in fnamespace.values():
macros_by_name[macro.name] = macro

So per that error message, the package appears to be "missing." I think that's reasonable behavior for the macro resolver, although the error message could be clearer: No macros found in a package named '{package_name}'

Options for how dispatch should handle this:

  • Before searching search_packages here, we check to see if the package is the GLOBAL_PROJECT_NAME or is present in self._namespace.macro_resolver.packages
  • We catch and smother the CompilationException here, rather than raising it. If dispatch fails to find any valid macros after searching everywhere, it will end up raising a different CompilationException later on.

I'm leaning toward the latter. What do you think?

@JCZuurmond
Copy link
Contributor Author

Before searching search_packages here, we check to see if the package is the GLOBAL_PROJECT_NAME or is present in self._namespace.macro_resolver.packages

I am wrapping my ahead around all inner dbt parts, so I can not judge well. What my gut feeling about this is, is that it is too tightly coupled: should the dispatch do this check? It is kind of the same logic as self._namespace.get_from_package does, so why add it here too?

We catch and smother the CompilationException here, rather than raising it. If dispatch fails to find any valid macros after searching everywhere, it will end up raising a different CompilationException later on.

It is raised there with the from exc

@jtcohen6
Copy link
Contributor

jtcohen6 commented Oct 22, 2021

I agree with your reasoning there!

My proposal would be, replace these lines with:

                except CompilationException as exc:
                    # we don't expect to find every macro we search for
                    pass

That is to say, while normally the macro resolver should raise an error if {{ fake_package.fake_macro() }} is called explicitly, I think it's reasonable for dispatch to step through the entire search order and report back with its more thorough error message:

In dispatch: No macro named 'fake_macro' found
    Searched for: fake_package.postgres__fake_macro, fake_package.default__fake_macro

@JCZuurmond JCZuurmond force-pushed the add-project-name-to-default-search-packages branch from d52ea56 to 2544741 Compare October 22, 2021 10:00
@JCZuurmond
Copy link
Contributor Author

I tested it locally and it does the trick! Now, we should add a test for this.

@JCZuurmond
Copy link
Contributor Author

JCZuurmond commented Oct 22, 2021

I have been looking at adding a test, I think the problem with adding it to the unit test is that the unit test assume no plugin/package (postgres, spark, redshift, etc.) is installed, but we pretend like it is because were getting a macro from that package (namespace).

I get the following error if I try this with the postgres plugin.

E               dbt.exceptions.InternalException: No plugin found for <MagicMock name='get_adapter().type()' id='4516255672'>

Should and can we mock this? Or should this test be moved to a package?

@jtcohen6
Copy link
Contributor

@JCZuurmond Ah ok, I don't think we're going to be able to figure that one very quickly. Let's add an integration test instead. There's a good starting point in test/integration/016_macro_tests/test_macros.py, that overrides get_columns_in_relation and makes sure it uses the new version. You could do everything the same, except reimplement postgres__get_columns_in_relation instead of get_columns_in_relation, and make sure it works by default (with no project-level dispatch config).

@JCZuurmond JCZuurmond force-pushed the add-project-name-to-default-search-packages branch from 9e72403 to 6558f71 Compare October 22, 2021 12:55
@JCZuurmond JCZuurmond force-pushed the add-project-name-to-default-search-packages branch from 6558f71 to 8bc2870 Compare October 22, 2021 13:01
@JCZuurmond
Copy link
Contributor Author

@jtcohen6 : ready to merge (if all tests pass)

Copy link
Contributor

@jtcohen6 jtcohen6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution @JCZuurmond!

@jtcohen6 jtcohen6 merged commit 5648b1c into dbt-labs:main Oct 22, 2021
jtcohen6 pushed a commit that referenced this pull request Oct 22, 2021
* Add project name to default search packages

We prefer macros in the project over the ones in the namespace (package)

* Add change to change log

* Use project_name instead of project

* Raise compilation error if no macros are found

* Update change log line

* Add test for package macro override

* Add JCZuurmond to contributor

* Fix typos

* Add test that should not over ride the package

* Add doc string to tests
@JCZuurmond JCZuurmond deleted the add-project-name-to-default-search-packages branch October 22, 2021 13:28
jtcohen6 added a commit that referenced this pull request Oct 22, 2021
* Add project name to default search packages

We prefer macros in the project over the ones in the namespace (package)

* Add change to change log

* Use project_name instead of project

* Raise compilation error if no macros are found

* Update change log line

* Add test for package macro override

* Add JCZuurmond to contributor

* Fix typos

* Add test that should not over ride the package

* Add doc string to tests

Co-authored-by: Cor <jczuurmond@protonmail.com>
def test_postgres_overrides(self):
# the first time, the model doesn't exist
self.run_dbt(expect_pass=False)
self.run_dbt(expect_pass=False)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the second time be expect pass True ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a check in the model that raises an explicit error if the macro is overridden, so I believe it fails both times:

{% set result = adapter.get_columns_in_relation(this) %}
{% if execute and result != 'a string' %}
{% do exceptions.raise_compiler_error('overriding get_columns_in_relation failed') %}
{% endif %}
select 1 as id

Copy link
Contributor Author

@JCZuurmond JCZuurmond Nov 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As explained in the class docstring, the run in this test should fail because the override does not happen. We need the override to overrule the raise compile error that @jtcohen6 showed.

    The macro in `override-postgres-get-columns-macros` does NOT override the
    `get_columns_in_relation` macro because we tell dispatch to not look at the
    postgres macros.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEATURE] Set all macro namespace by default to ['<name_of_your_root_project>', '<macro_namespace>']
3 participants