From 5b70dee100882d119acd5102a5109f2e53748942 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Tue, 3 Jan 2023 16:26:59 -0500 Subject: [PATCH] remove UnsetProfileConfig --- core/dbt/cli/main.py | 5 +- core/dbt/config/__init__.py | 2 +- core/dbt/config/runtime.py | 195 ++---------------------------------- core/dbt/task/base.py | 3 +- core/dbt/task/deps.py | 54 +--------- test/unit/test_config.py | 39 -------- 6 files changed, 17 insertions(+), 281 deletions(-) diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index 5292f795665..c1fe1742dce 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -241,10 +241,7 @@ def debug(ctx, **kwargs): @requires.project def deps(ctx, **kwargs): """Pull the most recent version of the dependencies listed in packages.yml""" - flags = ctx.obj["flags"] - project = ctx.obj["project"] - - task = DepsTask.from_project(project, flags.VARS) + task = DepsTask(ctx.obj["flags"], ctx.obj["project"]) results = task.run() success = task.interpret_results(results) diff --git a/core/dbt/config/__init__.py b/core/dbt/config/__init__.py index 5988ba589c3..1fa43bed3a5 100644 --- a/core/dbt/config/__init__.py +++ b/core/dbt/config/__init__.py @@ -1,4 +1,4 @@ # all these are just exports, they need "noqa" so flake8 will not complain. from .profile import Profile, read_user_config # noqa from .project import Project, IsFQNResource, PartialProject # noqa -from .runtime import RuntimeConfig, UnsetProfileConfig # noqa +from .runtime import RuntimeConfig # noqa diff --git a/core/dbt/config/runtime.py b/core/dbt/config/runtime.py index 46f03226b57..e13de6d0ae9 100644 --- a/core/dbt/config/runtime.py +++ b/core/dbt/config/runtime.py @@ -1,7 +1,7 @@ import itertools import os from copy import deepcopy -from dataclasses import dataclass, field +from dataclasses import dataclass from pathlib import Path from typing import ( Any, @@ -415,8 +415,8 @@ def _connection_keys(self): return () -# This is used by UnsetProfileConfig, for commands which do -# not require a profile, i.e. dbt deps and clean +# This is used by commands which do not require +# a profile, i.e. dbt deps and clean class UnsetProfile(Profile): def __init__(self): self.credentials = UnsetCredentials() @@ -435,189 +435,12 @@ def __getattribute__(self, name): return Profile.__getattribute__(self, name) -# This class is used by the dbt deps and clean commands, because they don't -# require a functioning profile. -@dataclass -class UnsetProfileConfig(RuntimeConfig): - """This class acts a lot _like_ a RuntimeConfig, except if your profile is - missing, any access to profile members results in an exception. - """ - - profile_name: str = field(repr=False) - target_name: str = field(repr=False) - - def __post_init__(self): - # instead of futzing with InitVar overrides or rewriting __init__, just - # `del` the attrs we don't want users touching. - del self.profile_name - del self.target_name - # don't call super().__post_init__(), as that calls validate(), and - # this object isn't very valid - - def __getattribute__(self, name): - # Override __getattribute__ to check that the attribute isn't 'banned'. - if name in {"profile_name", "target_name"}: - raise RuntimeException(f'Error: disallowed attribute "{name}" - no profile!') - - # avoid every attribute access triggering infinite recursion - return RuntimeConfig.__getattribute__(self, name) - - def to_target_dict(self): - # re-override the poisoned profile behavior - return DictDefaultEmptyStr({}) - - def to_project_config(self, with_packages=False): - """Return a dict representation of the config that could be written to - disk with `yaml.safe_dump` to get this configuration. - - Overrides dbt.config.Project.to_project_config to omit undefined profile - attributes. - - :param with_packages bool: If True, include the serialized packages - file in the root. - :returns dict: The serialized profile. - """ - result = deepcopy( - { - "name": self.project_name, - "version": self.version, - "project-root": self.project_root, - "profile": "", - "model-paths": self.model_paths, - "macro-paths": self.macro_paths, - "seed-paths": self.seed_paths, - "test-paths": self.test_paths, - "analysis-paths": self.analysis_paths, - "docs-paths": self.docs_paths, - "asset-paths": self.asset_paths, - "target-path": self.target_path, - "snapshot-paths": self.snapshot_paths, - "clean-targets": self.clean_targets, - "log-path": self.log_path, - "quoting": self.quoting, - "models": self.models, - "on-run-start": self.on_run_start, - "on-run-end": self.on_run_end, - "dispatch": self.dispatch, - "seeds": self.seeds, - "snapshots": self.snapshots, - "sources": self.sources, - "tests": self.tests, - "metrics": self.metrics, - "exposures": self.exposures, - "vars": self.vars.to_dict(), - "require-dbt-version": [v.to_version_string() for v in self.dbt_version], - "config-version": self.config_version, - } - ) - if self.query_comment: - result["query-comment"] = self.query_comment.to_dict(omit_none=True) - - if with_packages: - result.update(self.packages.to_dict(omit_none=True)) - - return result - - @classmethod - def from_parts( - cls, - project: Project, - profile: Profile, - args: Any, - dependencies: Optional[Mapping[str, "RuntimeConfig"]] = None, - ) -> "RuntimeConfig": - """Instantiate a RuntimeConfig from its components. - - :param profile: Ignored. - :param project: A parsed dbt Project. - :param args: The parsed command-line arguments. - :returns RuntimeConfig: The new configuration. - """ - cli_vars: Dict[str, Any] = getattr(args, "vars", {}) - - return cls( - project_name=project.project_name, - version=project.version, - project_root=project.project_root, - model_paths=project.model_paths, - macro_paths=project.macro_paths, - seed_paths=project.seed_paths, - test_paths=project.test_paths, - analysis_paths=project.analysis_paths, - docs_paths=project.docs_paths, - asset_paths=project.asset_paths, - target_path=project.target_path, - snapshot_paths=project.snapshot_paths, - clean_targets=project.clean_targets, - log_path=project.log_path, - packages_install_path=project.packages_install_path, - quoting=project.quoting, # we never use this anyway. - models=project.models, - on_run_start=project.on_run_start, - on_run_end=project.on_run_end, - dispatch=project.dispatch, - seeds=project.seeds, - snapshots=project.snapshots, - dbt_version=project.dbt_version, - packages=project.packages, - manifest_selectors=project.manifest_selectors, - selectors=project.selectors, - query_comment=project.query_comment, - sources=project.sources, - tests=project.tests, - metrics=project.metrics, - exposures=project.exposures, - vars=project.vars, - config_version=project.config_version, - unrendered=project.unrendered, - project_env_vars=project.project_env_vars, - profile_env_vars=profile.profile_env_vars, - profile_name="", - target_name="", - user_config=UserConfig(), - threads=getattr(args, "threads", 1), - credentials=UnsetCredentials(), - args=args, - cli_vars=cli_vars, - dependencies=dependencies, - ) - - @classmethod - def get_profile( - cls, - project_root: str, - cli_vars: Dict[str, Any], - args: Any, - ) -> Profile: - """ - Moving all logic regarding constructing a complete UnsetProfile to this function - This way we can have a clean load_profile function to call by the new CLI and remove - all logic for UnsetProfile once we migrate to new click CLI - """ - - profile = UnsetProfile() - # The profile (for warehouse connection) is not needed, but we want - # to get the UserConfig, which is also in profiles.yml - user_config = read_user_config(project_root) - profile.user_config = user_config - profile_renderer = ProfileRenderer(cli_vars) - profile.profile_env_vars = profile_renderer.ctx_obj.env_vars - return profile - - @classmethod - def from_args(cls: Type[RuntimeConfig], args: Any) -> "RuntimeConfig": - """Given arguments, read in dbt_project.yml from the current directory, - read in packages.yml if it exists, and use them to find the profile to - load. - - :param args: The arguments as parsed from the cli. - :raises DbtProjectError: If the project is invalid or missing. - :raises DbtProfileError: If the profile is invalid or missing. - :raises ValidationException: If the cli variables are invalid. - """ - project, profile = cls.collect_parts(args) - - return cls.from_parts(project=project, profile=profile, args=args) +UNUSED_RESOURCE_CONFIGURATION_PATH_MESSAGE = """\ +Configuration paths exist in your dbt_project.yml file which do not \ +apply to any resources. +There are {} unused configuration paths: +{} +""" def _is_config_used(path, fqns): diff --git a/core/dbt/task/base.py b/core/dbt/task/base.py index ef78c8d90bf..f6d37937e99 100644 --- a/core/dbt/task/base.py +++ b/core/dbt/task/base.py @@ -98,8 +98,7 @@ def set_log_format(cls): @classmethod def from_args(cls, args): try: - # This is usually RuntimeConfig but will be UnsetProfileConfig - # for the clean or deps tasks + # This is usually RuntimeConfig config = cls.ConfigType.from_args(args) except dbt.exceptions.DbtProjectError as exc: fire_event(DbtProjectError()) diff --git a/core/dbt/task/deps.py b/core/dbt/task/deps.py index d03ec3748dc..425f7771995 100644 --- a/core/dbt/task/deps.py +++ b/core/dbt/task/deps.py @@ -1,15 +1,10 @@ -from typing import Dict, Any, Optional - -from dbt import flags +from typing import Any, Optional import dbt.utils import dbt.deprecations import dbt.exceptions -from dbt.config.profile import read_user_config -from dbt.config.runtime import load_project, UnsetProfile from dbt.config.renderer import DbtProjectYamlRenderer -from dbt.config.utils import parse_cli_vars from dbt.deps.base import downloads_directory from dbt.deps.resolver import resolve_packages from dbt.deps.registry import RegistryPinnedPackage @@ -32,20 +27,13 @@ from dbt.config import Project -from dbt.task.base import NoneConfig class DepsTask(BaseTask): - ConfigType = NoneConfig - - def __init__( - self, - args: Any, - project: Project, - cli_vars: Dict[str, Any], - ): + def __init__(self, args: Any, project: Project): + move_to_nearest_project_dir(project.project_root) super().__init__(args=args, config=None, project=project) - self.cli_vars = cli_vars + self.cli_vars = args.vars def track_package_install( self, package_name: str, source_type: str, version: Optional[str] @@ -103,36 +91,4 @@ def run(self) -> None: ) if packages_to_upgrade: fire_event(EmptyLine()) - fire_event(DepsNotifyUpdatesAvailable(packages=ListOfStrings(packages_to_upgrade))) - - @classmethod - def _get_unset_profile(cls) -> UnsetProfile: - profile = UnsetProfile() - # The profile (for warehouse connection) is not needed, but we want - # to get the UserConfig, which is also in profiles.yml - user_config = read_user_config(flags.PROFILES_DIR) - profile.user_config = user_config - return profile - - @classmethod - def from_args(cls, args): - # deps needs to move to the project directory, as it does put files - # into the modules directory - nearest_project_dir = move_to_nearest_project_dir(args.project_dir) - - # N.B. parse_cli_vars is embedded into the param when using click. - # replace this with: - # cli_vars: Dict[str, Any] = getattr(args, "vars", {}) - # when this task is refactored for click - cli_vars: Dict[str, Any] = parse_cli_vars(getattr(args, "vars", "{}")) - project_root: str = args.project_dir or nearest_project_dir - profile: UnsetProfile = cls._get_unset_profile() - project = load_project(project_root, args.version_check, profile, cli_vars) - - return cls(args, project, cli_vars) - - @classmethod - def from_project(cls, project: Project, cli_vars: Dict[str, Any]) -> "DepsTask": - move_to_nearest_project_dir(project.project_root) - # TODO: remove args=None once BaseTask does not require args - return cls(None, project, cli_vars) + fire_event(DepsNotifyUpdatesAvailable(packages=ListOfStrings(packages_to_upgrade))) \ No newline at end of file diff --git a/test/unit/test_config.py b/test/unit/test_config.py index 880a09cc7ad..456f16fade6 100644 --- a/test/unit/test_config.py +++ b/test/unit/test_config.py @@ -1194,45 +1194,6 @@ def test_from_args(self): self.assertEqual(config.project_name, 'my_test_project') -class TestUnsetProfileConfig(BaseConfigTest): - def setUp(self): - self.profiles_dir = '/invalid-profiles-path' - self.project_dir = '/invalid-root-path' - super().setUp() - self.default_project_data['project-root'] = self.project_dir - - def get_project(self): - return project_from_config_norender(self.default_project_data, verify_version=self.args.version_check) - - def get_profile(self): - renderer = empty_profile_renderer() - return dbt.config.Profile.from_raw_profiles( - self.default_profile_data, self.default_project_data['profile'], renderer - ) - - def test_str(self): - project = self.get_project() - profile = self.get_profile() - config = dbt.config.UnsetProfileConfig.from_parts(project, profile, {}) - - str(config) - - def test_repr(self): - project = self.get_project() - profile = self.get_profile() - config = dbt.config.UnsetProfileConfig.from_parts(project, profile, {}) - - repr(config) - - def test_to_project_config(self): - project = self.get_project() - profile = self.get_profile() - config = dbt.config.UnsetProfileConfig.from_parts(project, profile, {}) - project_config = config.to_project_config() - - self.assertEqual(project_config["profile"], "") - - class TestVariableRuntimeConfigFiles(BaseFileTest): def setUp(self): super().setUp()