From c21df62e09792c020cf4d9c1bab71021bf4ae021 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Mon, 5 Dec 2022 17:04:47 -0500 Subject: [PATCH 01/13] first pass: dbt.cli.main.handle_and_check --- core/dbt/cli/main.py | 15 +++++++++++++-- core/dbt/cli/params.py | 6 +++--- core/dbt/tests/util.py | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index a7bbc9d6ae6..f19047f9a0b 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -15,8 +15,20 @@ from dbt.task.clean import CleanTask from dbt.task.deps import DepsTask from dbt.task.run import RunTask +from typing import Optional +def make_context(args, command) -> Optional[click.Context]: + ctx = command.make_context(command.name, args) + + ctx.invoked_subcommand = ctx.protected_args[0] if ctx.protected_args else None + return ctx + +def handle_and_check(args): + ctx = make_context(args, cli) + res, success = cli.invoke(ctx) + return res, success + def cli_runner(): # Alias "list" to "ls" ls = copy(cli.commands["list"]) @@ -151,7 +163,6 @@ def clean(ctx, **kwargs): success = task.interpret_results(results) return results, success - # dbt docs @cli.group() @click.pass_context @@ -220,6 +231,7 @@ def compile(ctx, **kwargs): """Generates executable SQL from source, model, test, and analysis files. Compiled SQL files are written to the target/ directory.""" flags = Flags() click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + return None, True # dbt debug @@ -334,7 +346,6 @@ def parse(ctx, **kwargs): @p.version_check def run(ctx, **kwargs): """Compile SQL and execute against the current target database.""" - config = RuntimeConfig.from_parts(ctx.obj["project"], ctx.obj["profile"], ctx.obj["flags"]) task = RunTask(ctx.obj["flags"], config) diff --git a/core/dbt/cli/params.py b/core/dbt/cli/params.py index dcfc16e6dab..3405a8fde46 100644 --- a/core/dbt/cli/params.py +++ b/core/dbt/cli/params.py @@ -131,7 +131,7 @@ "--log-path", envvar="DBT_LOG_PATH", help="Configure the 'log-path'. Only applies this setting for the current run. Overrides the 'DBT_LOG_PATH' if it is set.", - default=Path.cwd() / "logs", + default=lambda: Path.cwd() / "logs", type=click.Path(resolve_path=True, path_type=Path), ) @@ -214,7 +214,7 @@ "--profiles-dir", envvar="DBT_PROFILES_DIR", help="Which directory to look in for the profiles.yml file. If not set, dbt will look in the current working directory first, then HOME/.dbt/", - default=default_profiles_dir(), + default=lambda: default_profiles_dir(), type=click.Path(exists=True), ) @@ -222,7 +222,7 @@ "--project-dir", envvar=None, help="Which directory to look in for the dbt_project.yml file. Default is the current working directory and its parents.", - default=default_project_dir(), + default=lambda: default_project_dir(), type=click.Path(exists=True), ) diff --git a/core/dbt/tests/util.py b/core/dbt/tests/util.py index af837c18b17..6943ee1d7b7 100644 --- a/core/dbt/tests/util.py +++ b/core/dbt/tests/util.py @@ -8,7 +8,7 @@ from contextlib import contextmanager from dbt.adapters.factory import Adapter -from dbt.main import handle_and_check +from dbt.cli.main import handle_and_check from dbt.logger import log_manager from dbt.contracts.graph.manifest import Manifest from dbt.events.functions import fire_event, capture_stdout_logs, stop_capture_stdout_logs, reset_metadata_vars From 8c6dd4bee27c38d43b33f0f3039b2f81dc5ff747 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Wed, 7 Dec 2022 16:50:56 -0500 Subject: [PATCH 02/13] DBTContext --- core/dbt/cli/context.py | 44 +++++++++++++++++++++++++++++++++++++++++ core/dbt/cli/main.py | 10 ---------- core/dbt/tests/util.py | 8 ++++++-- 3 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 core/dbt/cli/context.py diff --git a/core/dbt/cli/context.py b/core/dbt/cli/context.py new file mode 100644 index 00000000000..e0cf27624ca --- /dev/null +++ b/core/dbt/cli/context.py @@ -0,0 +1,44 @@ +from typing import List +from click import Context +from click.exceptions import NoSuchOption, UsageError +from dbt.cli.main import cli +from dbt.config.project import Project + +class DBTUsageException(Exception): + pass + +class DBTContext(Context): + def __init__(self, args: List[str]) -> None: + try: + ctx = cli.make_context(cli.name, args) + if args: + cmd_name, cmd, cmd_args = cli.resolve_command(ctx, args) + cmd.make_context(cmd_name, cmd_args, parent=ctx) + except (NoSuchOption, UsageError) as e: + raise DBTUsageException(e.message) + + ctx.obj = {} + # yikes? + self.__dict__.update(ctx.__dict__) + # TODO: consider initializing Flags, ctx.obj here. + + # @classmethod + # def from_args(cls, args: List[str]) -> "DBTContext": + # try: + # ctx = cli.make_context(cli.name, args) + # if args: + # cmd_name, cmd, cmd_args = cli.resolve_command(ctx, args) + # cmd.make_context(cmd_name, cmd_args, parent=ctx) + # except (NoSuchOption, UsageError) as e: + # raise DBTUsageException(e.message) + + # ctx.obj = {} + # # yikes + # ctx.__class__ = cls + # return ctx + + def set_project(self, project: Project): + if not isinstance(project, Project): + raise ValueError(f"{project} is a {type(project)}, expected a Project object.") + + self.obj["project"] = project \ No newline at end of file diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index f19047f9a0b..90e7bd0fb13 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -18,16 +18,6 @@ from typing import Optional -def make_context(args, command) -> Optional[click.Context]: - ctx = command.make_context(command.name, args) - - ctx.invoked_subcommand = ctx.protected_args[0] if ctx.protected_args else None - return ctx - -def handle_and_check(args): - ctx = make_context(args, cli) - res, success = cli.invoke(ctx) - return res, success def cli_runner(): # Alias "list" to "ls" diff --git a/core/dbt/tests/util.py b/core/dbt/tests/util.py index 6943ee1d7b7..dbff80d111a 100644 --- a/core/dbt/tests/util.py +++ b/core/dbt/tests/util.py @@ -8,7 +8,7 @@ from contextlib import contextmanager from dbt.adapters.factory import Adapter -from dbt.cli.main import handle_and_check +from dbt.cli.context import DBTContext, cli as dbt from dbt.logger import log_manager from dbt.contracts.graph.manifest import Manifest from dbt.events.functions import fire_event, capture_stdout_logs, stop_capture_stdout_logs, reset_metadata_vars @@ -73,7 +73,11 @@ def run_dbt(args: List[str] = None, expect_pass=True): args = ["run"] print("\n\nInvoking dbt with {}".format(args)) - res, success = handle_and_check(args) + # ctx = DBTContext.from_args(args) + ctx = DBTContext(args) + + # ctx.set_project('test') + res, success = dbt.invoke(ctx) if expect_pass is not None: assert success == expect_pass, "dbt exit state did not match expected" From a6a5675003a698f21ae065b866b3b03b98b7ff62 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Thu, 8 Dec 2022 15:41:48 -0500 Subject: [PATCH 03/13] DBTContext with invocation_args --- core/dbt/cli/context.py | 61 ++++++++++++++++++++--------------------- core/dbt/cli/main.py | 6 ++++ core/dbt/tests/util.py | 9 +++--- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/core/dbt/cli/context.py b/core/dbt/cli/context.py index e0cf27624ca..f26b5156fde 100644 --- a/core/dbt/cli/context.py +++ b/core/dbt/cli/context.py @@ -1,44 +1,41 @@ -from typing import List -from click import Context +from click import Context, Group, Command from click.exceptions import NoSuchOption, UsageError -from dbt.cli.main import cli +from dbt.cli.flags import Flags from dbt.config.project import Project +import sys + class DBTUsageException(Exception): pass + class DBTContext(Context): - def __init__(self, args: List[str]) -> None: - try: - ctx = cli.make_context(cli.name, args) - if args: - cmd_name, cmd, cmd_args = cli.resolve_command(ctx, args) - cmd.make_context(cmd_name, cmd_args, parent=ctx) + def __init__(self, command: Command, **kwargs) -> None: + if isinstance(kwargs.get("parent"), DBTContext): + self.invocation_args = kwargs["parent"].invocation_args + else: + self.invocation_args = kwargs.pop("args", sys.argv[1:]) + + super().__init__(command, **kwargs) + + # Bubble up validation errors for top-level commands + if not self.parent: + self._validate_args(command, self.invocation_args) + + self.obj = self.obj or {} + self.flags = Flags(self) + + def _validate_args(self, command, args) -> None: + try: + command.parse_args(self, args) + if isinstance(command, Group): + _, cmd, cmd_args = command.resolve_command(self, args) + self._validate_args(cmd, cmd_args) except (NoSuchOption, UsageError) as e: - raise DBTUsageException(e.message) - - ctx.obj = {} - # yikes? - self.__dict__.update(ctx.__dict__) - # TODO: consider initializing Flags, ctx.obj here. - - # @classmethod - # def from_args(cls, args: List[str]) -> "DBTContext": - # try: - # ctx = cli.make_context(cli.name, args) - # if args: - # cmd_name, cmd, cmd_args = cli.resolve_command(ctx, args) - # cmd.make_context(cmd_name, cmd_args, parent=ctx) - # except (NoSuchOption, UsageError) as e: - # raise DBTUsageException(e.message) - - # ctx.obj = {} - # # yikes - # ctx.__class__ = cls - # return ctx + raise DBTUsageException(e.message) def set_project(self, project: Project): if not isinstance(project, Project): raise ValueError(f"{project} is a {type(project)}, expected a Project object.") - - self.obj["project"] = project \ No newline at end of file + + self.obj["project"] = project diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index 90e7bd0fb13..98fe4c59cf3 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -8,6 +8,7 @@ from dbt.cli.flags import Flags from dbt.config import RuntimeConfig from dbt.config.runtime import load_project, load_profile +from dbt.cli.context import DBTContext from dbt.events.functions import setup_event_logger from dbt.profiler import profiler from dbt.tracking import initialize_from_flags, track_run @@ -25,6 +26,11 @@ def cli_runner(): ls.hidden = True cli.add_command(ls, "ls") + # TODO: set context_class this on all commands outside this method + cli.context_class = DBTContext + for command in cli.commands.values(): + command.context_class = DBTContext + # Run the cli cli() diff --git a/core/dbt/tests/util.py b/core/dbt/tests/util.py index dbff80d111a..7fe22e2c2fe 100644 --- a/core/dbt/tests/util.py +++ b/core/dbt/tests/util.py @@ -8,7 +8,8 @@ from contextlib import contextmanager from dbt.adapters.factory import Adapter -from dbt.cli.context import DBTContext, cli as dbt +from dbt.cli.context import DBTContext +from dbt.cli.main import cli from dbt.logger import log_manager from dbt.contracts.graph.manifest import Manifest from dbt.events.functions import fire_event, capture_stdout_logs, stop_capture_stdout_logs, reset_metadata_vars @@ -73,11 +74,9 @@ def run_dbt(args: List[str] = None, expect_pass=True): args = ["run"] print("\n\nInvoking dbt with {}".format(args)) - # ctx = DBTContext.from_args(args) - ctx = DBTContext(args) - + ctx = DBTContext(cli, args=args) # ctx.set_project('test') - res, success = dbt.invoke(ctx) + res, success = cli.invoke(ctx) if expect_pass is not None: assert success == expect_pass, "dbt exit state did not match expected" From aff425efd4ae653ad1b1f6640a392983532fca9a Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Thu, 8 Dec 2022 15:55:46 -0500 Subject: [PATCH 04/13] merge with Profile, run --- core/dbt/cli/main.py | 3 ++- core/dbt/tests/fixtures/project.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index 98fe4c59cf3..0bd8bb27568 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -99,8 +99,9 @@ def cli(ctx, **kwargs): return # Profile + # TODO: fix flags.THREADS access profile = load_profile( - flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, flags.THREADS + flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, None ) # Project diff --git a/core/dbt/tests/fixtures/project.py b/core/dbt/tests/fixtures/project.py index fe97176cfb6..ffea566f4db 100644 --- a/core/dbt/tests/fixtures/project.py +++ b/core/dbt/tests/fixtures/project.py @@ -243,7 +243,7 @@ def selectors_yml(project_root, selectors): def adapter(unique_schema, project_root, profiles_root, profiles_yml, dbt_project_yml): # The profiles.yml and dbt_project.yml should already be written out args = Namespace( - profiles_dir=str(profiles_root), project_dir=str(project_root), target=None, profile=None + profiles_dir=str(profiles_root), project_dir=str(project_root), target=None, profile=None, threads=None ) flags.set_from_args(args, {}) runtime_config = RuntimeConfig.from_args(args) From 04ec5cb6da5c7efa512ed75ee572d45e9886a82f Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Thu, 8 Dec 2022 16:22:27 -0500 Subject: [PATCH 05/13] build self.obj in DBTContext --- core/dbt/cli/context.py | 30 ++++++++++++++---------------- core/dbt/cli/flags.py | 7 +++++-- core/dbt/cli/main.py | 23 ++--------------------- core/dbt/tests/util.py | 1 - 4 files changed, 21 insertions(+), 40 deletions(-) diff --git a/core/dbt/cli/context.py b/core/dbt/cli/context.py index f26b5156fde..a9f373f85da 100644 --- a/core/dbt/cli/context.py +++ b/core/dbt/cli/context.py @@ -1,7 +1,7 @@ from click import Context, Group, Command from click.exceptions import NoSuchOption, UsageError +from dbt.config.runtime import load_project, load_profile from dbt.cli.flags import Flags -from dbt.config.project import Project import sys @@ -11,19 +11,23 @@ class DBTUsageException(Exception): class DBTContext(Context): def __init__(self, command: Command, **kwargs) -> None: - if isinstance(kwargs.get("parent"), DBTContext): - self.invocation_args = kwargs["parent"].invocation_args - else: - self.invocation_args = kwargs.pop("args", sys.argv[1:]) - + invocation_args = kwargs.pop("args", sys.argv[1:]) super().__init__(command, **kwargs) # Bubble up validation errors for top-level commands if not self.parent: - self._validate_args(command, self.invocation_args) - - self.obj = self.obj or {} - self.flags = Flags(self) + self._validate_args(command, invocation_args) + + if not self.obj: + flags = Flags(self, args=invocation_args) + # TODO: fix flags.THREADS access + # TODO: set accept pluggable profile, project objects + profile = load_profile(flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, None) # type: ignore + project = load_project(flags.PROJECT_DIR, flags.VERSION_CHECK, profile, flags.VARS) # type: ignore + self.obj = {} + self.obj["flags"] = flags + self.obj["profile"] = profile + self.obj["project"] = project def _validate_args(self, command, args) -> None: try: @@ -33,9 +37,3 @@ def _validate_args(self, command, args) -> None: self._validate_args(cmd, cmd_args) except (NoSuchOption, UsageError) as e: raise DBTUsageException(e.message) - - def set_project(self, project: Project): - if not isinstance(project, Project): - raise ValueError(f"{project} is a {type(project)}, expected a Project object.") - - self.obj["project"] = project diff --git a/core/dbt/cli/flags.py b/core/dbt/cli/flags.py index a8af62bf61d..b206f181c6d 100644 --- a/core/dbt/cli/flags.py +++ b/core/dbt/cli/flags.py @@ -12,6 +12,7 @@ from dbt.config.profile import read_user_config from dbt.contracts.project import UserConfig +from typing import List if os.name != "nt": # https://bugs.python.org/issue41567 @@ -20,7 +21,9 @@ @dataclass(frozen=True) class Flags: - def __init__(self, ctx: Context = None, user_config: UserConfig = None) -> None: + def __init__( + self, ctx: Context = None, user_config: UserConfig = None, args: List[str] = sys.argv + ) -> None: if ctx is None: ctx = get_current_context() @@ -50,7 +53,7 @@ def assign_params(ctx, params_assigned_from_default): invoked_subcommand = getattr(import_module("dbt.cli.main"), invoked_subcommand_name) invoked_subcommand.allow_extra_args = True invoked_subcommand.ignore_unknown_options = True - invoked_subcommand_ctx = invoked_subcommand.make_context(None, sys.argv) + invoked_subcommand_ctx = invoked_subcommand.make_context(None, args) assign_params(invoked_subcommand_ctx, params_assigned_from_default) if not user_config: diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index 0bd8bb27568..f4e9e815bbc 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -7,7 +7,6 @@ from dbt.cli import params as p from dbt.cli.flags import Flags from dbt.config import RuntimeConfig -from dbt.config.runtime import load_project, load_profile from dbt.cli.context import DBTContext from dbt.events.functions import setup_event_logger from dbt.profiler import profiler @@ -26,10 +25,7 @@ def cli_runner(): ls.hidden = True cli.add_command(ls, "ls") - # TODO: set context_class this on all commands outside this method cli.context_class = DBTContext - for command in cli.commands.values(): - command.context_class = DBTContext # Run the cli cli() @@ -71,7 +67,7 @@ def cli(ctx, **kwargs): For more documentation on these commands, visit: docs.getdbt.com """ # Get primatives - flags = Flags() + flags = ctx.obj["flags"] # Logging # N.B. Legacy logger is not supported @@ -98,21 +94,6 @@ def cli(ctx, **kwargs): click.echo(f"`version` called\n ctx.params: {pf(ctx.params)}") return - # Profile - # TODO: fix flags.THREADS access - profile = load_profile( - flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, None - ) - - # Project - project = load_project(flags.PROJECT_DIR, flags.VERSION_CHECK, profile, flags.VARS) - - # Context for downstream commands - ctx.obj = {} - ctx.obj["flags"] = flags - ctx.obj["profile"] = profile - ctx.obj["project"] = project - # dbt build @cli.command("build") @@ -257,7 +238,7 @@ def debug(ctx, **kwargs): @p.vars def deps(ctx, **kwargs): """Pull the most recent version of the dependencies listed in packages.yml""" - flags = Flags() + flags = ctx.obj["flags"] project = ctx.obj["project"] task = DepsTask.from_project(project, flags.VARS) diff --git a/core/dbt/tests/util.py b/core/dbt/tests/util.py index 7fe22e2c2fe..2d8c51124d4 100644 --- a/core/dbt/tests/util.py +++ b/core/dbt/tests/util.py @@ -75,7 +75,6 @@ def run_dbt(args: List[str] = None, expect_pass=True): print("\n\nInvoking dbt with {}".format(args)) ctx = DBTContext(cli, args=args) - # ctx.set_project('test') res, success = cli.invoke(ctx) if expect_pass is not None: From 1fe76f6afb476074f724fd32ee7ad989945a91f1 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Mon, 12 Dec 2022 17:12:37 -0500 Subject: [PATCH 06/13] dbtRunner, initialize context in subcommand --- core/dbt/cli/context.py | 39 ---------------------- core/dbt/cli/flags.py | 7 ++-- core/dbt/cli/main.py | 71 +++++++++++++++++++++++++++++++++-------- core/dbt/tests/util.py | 7 ++-- 4 files changed, 63 insertions(+), 61 deletions(-) delete mode 100644 core/dbt/cli/context.py diff --git a/core/dbt/cli/context.py b/core/dbt/cli/context.py deleted file mode 100644 index a9f373f85da..00000000000 --- a/core/dbt/cli/context.py +++ /dev/null @@ -1,39 +0,0 @@ -from click import Context, Group, Command -from click.exceptions import NoSuchOption, UsageError -from dbt.config.runtime import load_project, load_profile -from dbt.cli.flags import Flags -import sys - - -class DBTUsageException(Exception): - pass - - -class DBTContext(Context): - def __init__(self, command: Command, **kwargs) -> None: - invocation_args = kwargs.pop("args", sys.argv[1:]) - super().__init__(command, **kwargs) - - # Bubble up validation errors for top-level commands - if not self.parent: - self._validate_args(command, invocation_args) - - if not self.obj: - flags = Flags(self, args=invocation_args) - # TODO: fix flags.THREADS access - # TODO: set accept pluggable profile, project objects - profile = load_profile(flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, None) # type: ignore - project = load_project(flags.PROJECT_DIR, flags.VERSION_CHECK, profile, flags.VARS) # type: ignore - self.obj = {} - self.obj["flags"] = flags - self.obj["profile"] = profile - self.obj["project"] = project - - def _validate_args(self, command, args) -> None: - try: - command.parse_args(self, args) - if isinstance(command, Group): - _, cmd, cmd_args = command.resolve_command(self, args) - self._validate_args(cmd, cmd_args) - except (NoSuchOption, UsageError) as e: - raise DBTUsageException(e.message) diff --git a/core/dbt/cli/flags.py b/core/dbt/cli/flags.py index b206f181c6d..a8af62bf61d 100644 --- a/core/dbt/cli/flags.py +++ b/core/dbt/cli/flags.py @@ -12,7 +12,6 @@ from dbt.config.profile import read_user_config from dbt.contracts.project import UserConfig -from typing import List if os.name != "nt": # https://bugs.python.org/issue41567 @@ -21,9 +20,7 @@ @dataclass(frozen=True) class Flags: - def __init__( - self, ctx: Context = None, user_config: UserConfig = None, args: List[str] = sys.argv - ) -> None: + def __init__(self, ctx: Context = None, user_config: UserConfig = None) -> None: if ctx is None: ctx = get_current_context() @@ -53,7 +50,7 @@ def assign_params(ctx, params_assigned_from_default): invoked_subcommand = getattr(import_module("dbt.cli.main"), invoked_subcommand_name) invoked_subcommand.allow_extra_args = True invoked_subcommand.ignore_unknown_options = True - invoked_subcommand_ctx = invoked_subcommand.make_context(None, args) + invoked_subcommand_ctx = invoked_subcommand.make_context(None, sys.argv) assign_params(invoked_subcommand_ctx, params_assigned_from_default) if not user_config: diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index f4e9e815bbc..43665694523 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -7,7 +7,9 @@ from dbt.cli import params as p from dbt.cli.flags import Flags from dbt.config import RuntimeConfig -from dbt.cli.context import DBTContext +from dbt.config.project import Project +from dbt.config.profile import Profile +from dbt.config.runtime import load_project, load_profile from dbt.events.functions import setup_event_logger from dbt.profiler import profiler from dbt.tracking import initialize_from_flags, track_run @@ -19,18 +21,63 @@ +# CLI invocation def cli_runner(): # Alias "list" to "ls" ls = copy(cli.commands["list"]) ls.hidden = True cli.add_command(ls, "ls") - cli.context_class = DBTContext - # Run the cli cli() +class dbtUsageException(Exception): + pass + + +# Programmatic invocation +class dbtRunner: + def __init__(self, project: Project = None, profile: Profile = None): + self.project = project + self.profile = profile + + def invoke(self, args): + dbt_ctx = cli.make_context(cli.name, args) + dbt_ctx.obj = {} + dbt_ctx.obj["project"] = self.project + dbt_ctx.obj["profile"] = self.profile + + try: + return cli.invoke(dbt_ctx) + except (click.NoSuchOption, click.UsageError) as e: + raise dbtUsageException(e.message) + + +# TODO: refactor - consider decorator, or post-init on a dbtContext +def _initialize_context(ctx): + flags = Flags() + + # Tracking + initialize_from_flags(flags.ANONYMOUS_USAGE_STATS, flags.PROFILES_DIR) + ctx.with_resource(track_run(run_command=flags.WHICH)) + + ctx.obj = ctx.obj or {} + + # Profile + # TODO: generalize safe access to threads + threads = getattr(flags, "THREADS", None) + profile = load_profile(flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, threads) + # Project + if ctx.obj.get("project") is None: + project = load_project(flags.PROJECT_DIR, flags.VERSION_CHECK, profile, flags.VARS) + ctx.obj["project"] = project + + # Context for downstream commands + ctx.obj["flags"] = flags + ctx.obj["profile"] = profile + + # dbt @click.group( context_settings={"help_option_names": ["-h", "--help"]}, @@ -67,7 +114,12 @@ def cli(ctx, **kwargs): For more documentation on these commands, visit: docs.getdbt.com """ # Get primatives - flags = ctx.obj["flags"] + flags = Flags() + + # Version info + if flags.VERSION: + click.echo(f"`version` called\n ctx.params: {pf(ctx.params)}") + return # Logging # N.B. Legacy logger is not supported @@ -78,10 +130,6 @@ def cli(ctx, **kwargs): flags.DEBUG, ) - # Tracking - initialize_from_flags(flags.ANONYMOUS_USAGE_STATS, flags.PROFILES_DIR) - ctx.with_resource(track_run(run_command=ctx.invoked_subcommand)) - # Profiling if flags.RECORD_TIMING_INFO: ctx.with_resource(profiler(enable=True, outfile=flags.RECORD_TIMING_INFO)) @@ -89,11 +137,6 @@ def cli(ctx, **kwargs): # Adapter management ctx.with_resource(adapter_management()) - # Version info - if flags.VERSION: - click.echo(f"`version` called\n ctx.params: {pf(ctx.params)}") - return - # dbt build @cli.command("build") @@ -238,6 +281,7 @@ def debug(ctx, **kwargs): @p.vars def deps(ctx, **kwargs): """Pull the most recent version of the dependencies listed in packages.yml""" + _initialize_context(ctx) flags = ctx.obj["flags"] project = ctx.obj["project"] @@ -324,6 +368,7 @@ def parse(ctx, **kwargs): @p.version_check def run(ctx, **kwargs): """Compile SQL and execute against the current target database.""" + _initialize_context(ctx) config = RuntimeConfig.from_parts(ctx.obj["project"], ctx.obj["profile"], ctx.obj["flags"]) task = RunTask(ctx.obj["flags"], config) diff --git a/core/dbt/tests/util.py b/core/dbt/tests/util.py index 2d8c51124d4..6cdc4ee5b77 100644 --- a/core/dbt/tests/util.py +++ b/core/dbt/tests/util.py @@ -8,8 +8,7 @@ from contextlib import contextmanager from dbt.adapters.factory import Adapter -from dbt.cli.context import DBTContext -from dbt.cli.main import cli +from dbt.cli.main import dbtRunner from dbt.logger import log_manager from dbt.contracts.graph.manifest import Manifest from dbt.events.functions import fire_event, capture_stdout_logs, stop_capture_stdout_logs, reset_metadata_vars @@ -74,8 +73,8 @@ def run_dbt(args: List[str] = None, expect_pass=True): args = ["run"] print("\n\nInvoking dbt with {}".format(args)) - ctx = DBTContext(cli, args=args) - res, success = cli.invoke(ctx) + dbt = dbtRunner() + res, success = dbt.invoke(args) if expect_pass is not None: assert success == expect_pass, "dbt exit state did not match expected" From 988e40affaf57270b54acf2c504a3c31a4cfaee6 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Tue, 13 Dec 2022 16:52:36 -0500 Subject: [PATCH 07/13] dbt.cli.requires - preflight, profile, project --- core/dbt/cli/main.py | 144 +++++++++++++++------------------------ core/dbt/cli/requires.py | 85 +++++++++++++++++++++++ 2 files changed, 141 insertions(+), 88 deletions(-) create mode 100644 core/dbt/cli/requires.py diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index 43665694523..474ee772d6a 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -3,23 +3,14 @@ from pprint import pformat as pf # This is temporary for RAT-ing import click -from dbt.adapters.factory import adapter_management -from dbt.cli import params as p -from dbt.cli.flags import Flags +from dbt.cli import requires, params as p from dbt.config import RuntimeConfig from dbt.config.project import Project from dbt.config.profile import Profile -from dbt.config.runtime import load_project, load_profile -from dbt.events.functions import setup_event_logger -from dbt.profiler import profiler -from dbt.tracking import initialize_from_flags, track_run - +from dbt.contracts.graph.manifest import Manifest from dbt.task.clean import CleanTask from dbt.task.deps import DepsTask from dbt.task.run import RunTask -from typing import Optional - - # CLI invocation def cli_runner(): @@ -38,15 +29,19 @@ class dbtUsageException(Exception): # Programmatic invocation class dbtRunner: - def __init__(self, project: Project = None, profile: Profile = None): + def __init__( + self, project: Project = None, profile: Profile = None, manifest: Manifest = None + ): self.project = project self.profile = profile + self.manifest = manifest def invoke(self, args): dbt_ctx = cli.make_context(cli.name, args) dbt_ctx.obj = {} dbt_ctx.obj["project"] = self.project dbt_ctx.obj["profile"] = self.profile + dbt_ctx.obj["manifest"] = self.manifest try: return cli.invoke(dbt_ctx) @@ -54,30 +49,6 @@ def invoke(self, args): raise dbtUsageException(e.message) -# TODO: refactor - consider decorator, or post-init on a dbtContext -def _initialize_context(ctx): - flags = Flags() - - # Tracking - initialize_from_flags(flags.ANONYMOUS_USAGE_STATS, flags.PROFILES_DIR) - ctx.with_resource(track_run(run_command=flags.WHICH)) - - ctx.obj = ctx.obj or {} - - # Profile - # TODO: generalize safe access to threads - threads = getattr(flags, "THREADS", None) - profile = load_profile(flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, threads) - # Project - if ctx.obj.get("project") is None: - project = load_project(flags.PROJECT_DIR, flags.VERSION_CHECK, profile, flags.VARS) - ctx.obj["project"] = project - - # Context for downstream commands - ctx.obj["flags"] = flags - ctx.obj["profile"] = profile - - # dbt @click.group( context_settings={"help_option_names": ["-h", "--help"]}, @@ -113,30 +84,11 @@ def cli(ctx, **kwargs): """An ELT tool for managing your SQL transformations and data models. For more documentation on these commands, visit: docs.getdbt.com """ - # Get primatives - flags = Flags() - # Version info - if flags.VERSION: + if ctx.params["version"]: click.echo(f"`version` called\n ctx.params: {pf(ctx.params)}") return - # Logging - # N.B. Legacy logger is not supported - setup_event_logger( - flags.LOG_PATH, - flags.LOG_FORMAT, - flags.USE_COLORS, - flags.DEBUG, - ) - - # Profiling - if flags.RECORD_TIMING_INFO: - ctx.with_resource(profiler(enable=True, outfile=flags.RECORD_TIMING_INFO)) - - # Adapter management - ctx.with_resource(adapter_management()) - # dbt build @cli.command("build") @@ -159,10 +111,11 @@ def cli(ctx, **kwargs): @p.threads @p.vars @p.version_check +@requires.preflight def build(ctx, **kwargs): """Run all Seeds, Models, Snapshots, and tests in DAG order""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt clean @@ -173,12 +126,12 @@ def build(ctx, **kwargs): @p.project_dir @p.target @p.vars +@requires.preflight +@requires.profile +@requires.project def clean(ctx, **kwargs): """Delete all folders in the clean-targets list (usually the dbt_packages and target directories.)""" - flags = Flags() - project = ctx.obj["project"] - - task = CleanTask(flags, project) + task = CleanTask(ctx.obj["flags"], ctx.obj["project"]) results = task.run() success = task.interpret_results(results) @@ -208,10 +161,11 @@ def docs(ctx, **kwargs): @p.threads @p.vars @p.version_check +@requires.preflight def docs_generate(ctx, **kwargs): """Generate the documentation website for your project""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt docs serve @@ -224,10 +178,11 @@ def docs_generate(ctx, **kwargs): @p.project_dir @p.target @p.vars +@requires.preflight def docs_serve(ctx, **kwargs): """Serve the documentation website for your project""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt compile @@ -248,10 +203,10 @@ def docs_serve(ctx, **kwargs): @p.threads @p.vars @p.version_check +@requires.preflight def compile(ctx, **kwargs): """Generates executable SQL from source, model, test, and analysis files. Compiled SQL files are written to the target/ directory.""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") return None, True @@ -265,10 +220,11 @@ def compile(ctx, **kwargs): @p.target @p.vars @p.version_check +@requires.preflight def debug(ctx, **kwargs): """Show some helpful information about dbt for debugging. Not to be confused with the --debug option which increases verbosity.""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt deps @@ -279,9 +235,11 @@ def debug(ctx, **kwargs): @p.project_dir @p.target @p.vars +@requires.preflight +@requires.profile +@requires.project def deps(ctx, **kwargs): """Pull the most recent version of the dependencies listed in packages.yml""" - _initialize_context(ctx) flags = ctx.obj["flags"] project = ctx.obj["project"] @@ -301,10 +259,11 @@ def deps(ctx, **kwargs): @p.skip_profile_setup @p.target @p.vars +@requires.preflight def init(ctx, **kwargs): """Initialize a new DBT project.""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt list @@ -323,10 +282,11 @@ def init(ctx, **kwargs): @p.state @p.target @p.vars +@requires.preflight def list(ctx, **kwargs): """List the resources in your project""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt parse @@ -342,10 +302,11 @@ def list(ctx, **kwargs): @p.vars @p.version_check @p.write_manifest +@requires.preflight def parse(ctx, **kwargs): """Parses the project and provides information on performance""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt run @@ -366,9 +327,11 @@ def parse(ctx, **kwargs): @p.threads @p.vars @p.version_check +@requires.preflight +@requires.profile +@requires.project def run(ctx, **kwargs): """Compile SQL and execute against the current target database.""" - _initialize_context(ctx) config = RuntimeConfig.from_parts(ctx.obj["project"], ctx.obj["profile"], ctx.obj["flags"]) task = RunTask(ctx.obj["flags"], config) @@ -386,10 +349,11 @@ def run(ctx, **kwargs): @p.project_dir @p.target @p.vars +@requires.preflight def run_operation(ctx, **kwargs): """Run the named macro with any supplied arguments.""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt seed @@ -409,10 +373,11 @@ def run_operation(ctx, **kwargs): @p.threads @p.vars @p.version_check +@requires.preflight def seed(ctx, **kwargs): """Load data from csv files into your data warehouse.""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt snapshot @@ -429,10 +394,11 @@ def seed(ctx, **kwargs): @p.target @p.threads @p.vars +@requires.preflight def snapshot(ctx, **kwargs): """Execute snapshots defined in your project""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt source @@ -456,10 +422,11 @@ def source(ctx, **kwargs): @p.target @p.threads @p.vars +@requires.preflight def freshness(ctx, **kwargs): """Snapshots the current freshness of the project's sources""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # dbt test @@ -481,10 +448,11 @@ def freshness(ctx, **kwargs): @p.threads @p.vars @p.version_check +@requires.preflight def test(ctx, **kwargs): """Runs tests on data in deployed models. Run this after `dbt run`""" - flags = Flags() - click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}") + click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") + return None, True # Support running as a module diff --git a/core/dbt/cli/requires.py b/core/dbt/cli/requires.py new file mode 100644 index 00000000000..d9db7dfd67f --- /dev/null +++ b/core/dbt/cli/requires.py @@ -0,0 +1,85 @@ +from dbt.adapters.factory import adapter_management +from dbt.cli.flags import Flags +from dbt.config.runtime import load_project, load_profile +from dbt.events.functions import setup_event_logger +from dbt.exceptions import DbtProjectError +from dbt.profiler import profiler +from dbt.tracking import initialize_from_flags, track_run +from click import Context + + +def preflight(func): + def wrapper(*args, **kwargs): + ctx = args[0] + assert isinstance(ctx, Context) + ctx.obj = ctx.obj or {} + + # Flags + flags = Flags(ctx) + ctx.obj["flags"] = flags + + # Tracking + initialize_from_flags(flags.ANONYMOUS_USAGE_STATS, flags.PROFILES_DIR) + ctx.with_resource(track_run(run_command=flags.WHICH)) + + # Logging + # N.B. Legacy logger is not supported + setup_event_logger( + flags.LOG_PATH, + flags.LOG_FORMAT, + flags.USE_COLORS, + flags.DEBUG, + ) + + # Profiling + if flags.RECORD_TIMING_INFO: + ctx.with_resource(profiler(enable=True, outfile=flags.RECORD_TIMING_INFO)) + + # Adapter management + ctx.with_resource(adapter_management()) + + return func(*args, **kwargs) + + return wrapper + + +def profile(func): + def wrapper(*args, **kwargs): + ctx = args[0] + assert isinstance(ctx, Context) + + if ctx.obj.get("profile") is None: + flags = ctx.obj["flags"] + # TODO: Generalize safe access to flags.THREADS: + # https://github.com/dbt-labs/dbt-core/issues/6259 + threads = getattr(flags, "THREADS", None) + profile = load_profile( + flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, threads + ) + ctx.obj["profile"] = profile + + return func(*args, **kwargs) + + return wrapper + + +def project(func): + def wrapper(*args, **kwargs): + ctx = args[0] + assert isinstance(ctx, Context) + + if ctx.obj.get("project") is None: + # TODO: Decouple target from profile, and remove the need for profile here: + # https://github.com/dbt-labs/dbt-core/issues/6257 + if not ctx.obj.get("profile"): + raise DbtProjectError("profile required for project") + + flags = ctx.obj["flags"] + project = load_project( + flags.PROJECT_DIR, flags.VERSION_CHECK, ctx.obj["profile"], flags.VARS + ) + ctx.obj["project"] = project + + return func(*args, **kwargs) + + return wrapper \ No newline at end of file From c5ced63059bec02a4f6225118d46adeca66c09c0 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Tue, 13 Dec 2022 17:05:23 -0500 Subject: [PATCH 08/13] run functional + adapter tests prior to test/integration --- core/dbt/cli/params.py | 4 ++-- core/dbt/cli/requires.py | 4 ++-- tox.ini | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/dbt/cli/params.py b/core/dbt/cli/params.py index 3405a8fde46..a4119426895 100644 --- a/core/dbt/cli/params.py +++ b/core/dbt/cli/params.py @@ -214,7 +214,7 @@ "--profiles-dir", envvar="DBT_PROFILES_DIR", help="Which directory to look in for the profiles.yml file. If not set, dbt will look in the current working directory first, then HOME/.dbt/", - default=lambda: default_profiles_dir(), + default=default_profiles_dir, type=click.Path(exists=True), ) @@ -222,7 +222,7 @@ "--project-dir", envvar=None, help="Which directory to look in for the dbt_project.yml file. Default is the current working directory and its parents.", - default=lambda: default_project_dir(), + default=default_project_dir, type=click.Path(exists=True), ) diff --git a/core/dbt/cli/requires.py b/core/dbt/cli/requires.py index d9db7dfd67f..1bf4abe1779 100644 --- a/core/dbt/cli/requires.py +++ b/core/dbt/cli/requires.py @@ -50,7 +50,7 @@ def wrapper(*args, **kwargs): if ctx.obj.get("profile") is None: flags = ctx.obj["flags"] - # TODO: Generalize safe access to flags.THREADS: + # TODO: Generalize safe access to flags.THREADS: # https://github.com/dbt-labs/dbt-core/issues/6259 threads = getattr(flags, "THREADS", None) profile = load_profile( @@ -82,4 +82,4 @@ def wrapper(*args, **kwargs): return func(*args, **kwargs) - return wrapper \ No newline at end of file + return wrapper diff --git a/tox.ini b/tox.ini index 84fc54c5957..c77b9f92272 100644 --- a/tox.ini +++ b/tox.ini @@ -25,9 +25,10 @@ passenv = POSTGRES_TEST_* PYTEST_ADDOPTS commands = - {envpython} -m pytest --cov=core -m profile_postgres {posargs} test/integration {envpython} -m pytest --cov=core {posargs} tests/functional {envpython} -m pytest --cov=core {posargs} tests/adapter + {envpython} -m pytest --cov=core -m profile_postgres {posargs} test/integration + deps = -rdev-requirements.txt From 9d79def53f017effc7fb2b2d4e5305142c5b1c36 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Tue, 13 Dec 2022 17:41:08 -0500 Subject: [PATCH 09/13] use update_wrapper in requires decorators to preserve dunders --- core/dbt/cli/requires.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/dbt/cli/requires.py b/core/dbt/cli/requires.py index 1bf4abe1779..690c12bfa10 100644 --- a/core/dbt/cli/requires.py +++ b/core/dbt/cli/requires.py @@ -5,7 +5,9 @@ from dbt.exceptions import DbtProjectError from dbt.profiler import profiler from dbt.tracking import initialize_from_flags, track_run + from click import Context +from functools import update_wrapper def preflight(func): @@ -40,7 +42,7 @@ def wrapper(*args, **kwargs): return func(*args, **kwargs) - return wrapper + return update_wrapper(wrapper, func) def profile(func): @@ -60,7 +62,7 @@ def wrapper(*args, **kwargs): return func(*args, **kwargs) - return wrapper + return update_wrapper(wrapper, func) def project(func): @@ -82,4 +84,4 @@ def wrapper(*args, **kwargs): return func(*args, **kwargs) - return wrapper + return update_wrapper(wrapper, func) From ad776a3e777ab3b4bb534111c2537b7bdb361d92 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Tue, 13 Dec 2022 18:31:19 -0500 Subject: [PATCH 10/13] test_dbt_runner --- core/dbt/cli/main.py | 14 +++++++------- test.py | 0 tests/unit/test_dbt_runner.py | 24 ++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 test.py create mode 100644 tests/unit/test_dbt_runner.py diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index 474ee772d6a..ea0223265c3 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -1,6 +1,7 @@ import inspect # This is temporary for RAT-ing from copy import copy from pprint import pformat as pf # This is temporary for RAT-ing +from typing import List, Tuple, Optional import click from dbt.cli import requires, params as p @@ -36,14 +37,13 @@ def __init__( self.profile = profile self.manifest = manifest - def invoke(self, args): - dbt_ctx = cli.make_context(cli.name, args) - dbt_ctx.obj = {} - dbt_ctx.obj["project"] = self.project - dbt_ctx.obj["profile"] = self.profile - dbt_ctx.obj["manifest"] = self.manifest - + def invoke(self, args: List[str]) -> Tuple[Optional[List], bool]: try: + dbt_ctx = cli.make_context(cli.name, args) + dbt_ctx.obj = {} + dbt_ctx.obj["project"] = self.project + dbt_ctx.obj["profile"] = self.profile + dbt_ctx.obj["manifest"] = self.manifest return cli.invoke(dbt_ctx) except (click.NoSuchOption, click.UsageError) as e: raise dbtUsageException(e.message) diff --git a/test.py b/test.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit/test_dbt_runner.py b/tests/unit/test_dbt_runner.py new file mode 100644 index 00000000000..2e4bb5e71a3 --- /dev/null +++ b/tests/unit/test_dbt_runner.py @@ -0,0 +1,24 @@ +import pytest + +from dbt.cli.main import dbtRunner, dbtUsageException + + +class TestDbtRunner: + @pytest.fixture + def dbt(self) -> dbtRunner: + return dbtRunner() + + def test_group_invalid_option(self, dbt: dbtRunner) -> None: + with pytest.raises(dbtUsageException): + dbt.invoke(["--invalid-option"]) + + def test_command_invalid_option(self, dbt: dbtRunner) -> None: + with pytest.raises(dbtUsageException): + dbt.invoke(["deps", "--invalid-option"]) + + def test_invalid_command(self, dbt: dbtRunner) -> None: + with pytest.raises(dbtUsageException): + dbt.invoke(["invalid-command"]) + + def test_invoke_version(self, dbt: dbtRunner) -> None: + dbt.invoke(["--version"]) From a42a43a2769f73bef6c82696d1d52a41aa5d16ba Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Wed, 14 Dec 2022 11:20:58 -0500 Subject: [PATCH 11/13] changelog entry --- .changes/unreleased/Under the Hood-20221214-112048.yaml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changes/unreleased/Under the Hood-20221214-112048.yaml diff --git a/.changes/unreleased/Under the Hood-20221214-112048.yaml b/.changes/unreleased/Under the Hood-20221214-112048.yaml new file mode 100644 index 00000000000..9ac833b6e60 --- /dev/null +++ b/.changes/unreleased/Under the Hood-20221214-112048.yaml @@ -0,0 +1,7 @@ +kind: Under the Hood +body: functional tests run using click cli through dbtRunner +time: 2022-12-14T11:20:48.521869-05:00 +custom: + Author: MichelleArk + Issue: "6096" + PR: "6387" From c2a8ef6cbb78c1d5f78b142f2a37182a19684a22 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Thu, 15 Dec 2022 18:51:18 -0500 Subject: [PATCH 12/13] merge + remove empty file --- test.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index e69de29bb2d..00000000000 From 2799bf254c12d6024b0c5e2366b6f9b6b75cc096 Mon Sep 17 00:00:00 2001 From: Michelle Ark Date: Fri, 16 Dec 2022 17:28:43 -0500 Subject: [PATCH 13/13] linting --- core/dbt/cli/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index ea0223265c3..ce160fb8011 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -13,6 +13,7 @@ from dbt.task.deps import DepsTask from dbt.task.run import RunTask + # CLI invocation def cli_runner(): # Alias "list" to "ls" @@ -137,6 +138,7 @@ def clean(ctx, **kwargs): success = task.interpret_results(results) return results, success + # dbt docs @cli.group() @click.pass_context