Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions sqlmesh/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from sqlmesh.cli.example_project import ProjectTemplate, init_example_project
from sqlmesh.core.analytics import cli_analytics
from sqlmesh.core.console import configure_console, get_console
from sqlmesh.utils import Verbosity
from sqlmesh.core.config import load_configs
from sqlmesh.core.context import Context
from sqlmesh.utils.date import TimeLike
Expand Down Expand Up @@ -442,15 +443,19 @@ def diff(ctx: click.Context, environment: t.Optional[str] = None) -> None:
@error_handler
@cli_analytics
def plan(
ctx: click.Context, verbose: bool, environment: t.Optional[str] = None, **kwargs: t.Any
ctx: click.Context,
verbose: int,
environment: t.Optional[str] = None,
**kwargs: t.Any,
) -> None:
"""Apply local changes to the target environment."""
context = ctx.obj
restate_models = kwargs.pop("restate_model") or None
select_models = kwargs.pop("select_model") or None
allow_destructive_models = kwargs.pop("allow_destructive_model") or None
backfill_models = kwargs.pop("backfill_model") or None
setattr(get_console(), "verbose", verbose)
setattr(get_console(), "verbosity", Verbosity(verbose))

context.plan(
environment,
restate_models=restate_models,
Expand Down Expand Up @@ -643,15 +648,15 @@ def create_test(
def test(
obj: Context,
k: t.List[str],
verbose: bool,
verbose: int,
preserve_fixtures: bool,
tests: t.List[str],
) -> None:
"""Run model unit tests."""
result = obj.test(
match_patterns=k,
tests=tests,
verbose=verbose,
verbosity=Verbosity(verbose),
preserve_fixtures=preserve_fixtures,
)
if not result.wasSuccessful():
Expand Down Expand Up @@ -703,13 +708,13 @@ def fetchdf(ctx: click.Context, sql: str) -> None:
@click.pass_obj
@error_handler
@cli_analytics
def info(obj: Context, skip_connection: bool, verbose: bool) -> None:
def info(obj: Context, skip_connection: bool, verbose: int) -> None:
"""
Print information about a SQLMesh project.

Includes counts of project models and macros and connection tests for the data warehouse.
"""
obj.print_info(skip_connection=skip_connection, verbose=verbose)
obj.print_info(skip_connection=skip_connection, verbosity=Verbosity(verbose))


@cli.command("ui")
Expand Down Expand Up @@ -904,7 +909,11 @@ def rewrite(obj: Context, sql: str, read: str = "", write: str = "") -> None:
@error_handler
@cli_analytics
def prompt(
ctx: click.Context, prompt: str, evaluate: bool, temperature: float, verbose: bool
ctx: click.Context,
prompt: str,
evaluate: bool,
temperature: float,
verbose: int,
) -> None:
"""Uses LLM to generate a SQL query from a prompt."""
from sqlmesh.integrations.llm import LLMIntegration
Expand All @@ -915,7 +924,7 @@ def prompt(
context.models.values(),
context.engine_adapter.dialect,
temperature=temperature,
verbose=verbose,
verbosity=Verbosity(verbose),
)
query = llm_integration.query(prompt)

Expand Down
4 changes: 2 additions & 2 deletions sqlmesh/cli/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@
verbose = click.option(
"-v",
"--verbose",
is_flag=True,
help="Verbose output.",
count=True,
help="Verbose output. Use -vv for very verbose output.",
)
49 changes: 31 additions & 18 deletions sqlmesh/core/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
)
from sqlmesh.core.test import ModelTest
from sqlmesh.utils import rich as srich
from sqlmesh.utils import Verbosity
from sqlmesh.utils.concurrency import NodeExecutionFailedError
from sqlmesh.utils.date import time_like_to_str, to_date, yesterday_ds
from sqlmesh.utils.errors import (
Expand Down Expand Up @@ -310,10 +311,13 @@ def show_row_diff(
def print_environments(self, environments_summary: t.Dict[str, int]) -> None:
"""Prints all environment names along with expiry datetime."""

def _limit_model_names(self, tree: Tree, verbose: bool = False) -> Tree:
def _limit_model_names(self, tree: Tree, verbosity: Verbosity = Verbosity.DEFAULT) -> Tree:
"""Trim long indirectly modified model lists below threshold."""
modified_length = len(tree.children)
if not verbose and modified_length > self.INDIRECTLY_MODIFIED_DISPLAY_THRESHOLD:
if (
verbosity < Verbosity.VERY_VERBOSE
and modified_length > self.INDIRECTLY_MODIFIED_DISPLAY_THRESHOLD
):
tree.children = [
tree.children[0],
Tree(f".... {modified_length-2} more ...."),
Expand Down Expand Up @@ -516,7 +520,7 @@ class TerminalConsole(Console):
def __init__(
self,
console: t.Optional[RichConsole] = None,
verbose: bool = False,
verbosity: Verbosity = Verbosity.DEFAULT,
dialect: DialectType = None,
ignore_warnings: bool = False,
**kwargs: t.Any,
Expand Down Expand Up @@ -548,7 +552,7 @@ def __init__(

self.loading_status: t.Dict[uuid.UUID, Status] = {}

self.verbose = verbose
self.verbosity = verbosity
self.dialect = dialect
self.ignore_warnings = ignore_warnings

Expand Down Expand Up @@ -673,7 +677,7 @@ def start_creation_progress(
def update_creation_progress(self, snapshot: SnapshotInfoLike) -> None:
"""Update the snapshot creation progress."""
if self.creation_progress is not None and self.creation_task is not None:
if self.verbose:
if self.verbosity >= Verbosity.VERBOSE:
self.creation_progress.live.console.print(
f"{snapshot.display_name(self.environment_naming_info, self.default_catalog, dialect=self.dialect)} [green]created[/green]"
)
Expand Down Expand Up @@ -749,7 +753,7 @@ def start_promotion_progress(
def update_promotion_progress(self, snapshot: SnapshotInfoLike, promoted: bool) -> None:
"""Update the snapshot promotion progress."""
if self.promotion_progress is not None and self.promotion_task is not None:
if self.verbose:
if self.verbosity >= Verbosity.VERBOSE:
action_str = "[green]promoted[/green]" if promoted else "[yellow]demoted[/yellow]"
self.promotion_progress.live.console.print(
f"{snapshot.display_name(self.environment_naming_info, self.default_catalog, dialect=self.dialect)} {action_str}"
Expand Down Expand Up @@ -971,15 +975,15 @@ def _show_summary_tree_for(
added_tree.add(
f"[added]{snapshot.display_name(environment_naming_info, default_catalog, dialect=self.dialect)}"
)
tree.add(self._limit_model_names(added_tree, self.verbose))
tree.add(self._limit_model_names(added_tree, self.verbosity))
if removed_snapshot_ids:
removed_tree = Tree("[bold][removed]Removed:")
for s_id in sorted(removed_snapshot_ids):
snapshot_table_info = context_diff.removed_snapshots[s_id]
removed_tree.add(
f"[removed]{snapshot_table_info.display_name(environment_naming_info, default_catalog, dialect=self.dialect)}"
)
tree.add(self._limit_model_names(removed_tree, self.verbose))
tree.add(self._limit_model_names(removed_tree, self.verbosity))
if modified_snapshot_ids:
direct = Tree("[bold][direct]Directly Modified:")
indirect = Tree("[bold][indirect]Indirectly Modified:")
Expand Down Expand Up @@ -1007,7 +1011,7 @@ def _show_summary_tree_for(
if direct.children:
tree.add(direct)
if indirect.children:
tree.add(self._limit_model_names(indirect, self.verbose))
tree.add(self._limit_model_names(indirect, self.verbosity))
if metadata.children:
tree.add(metadata)
self._print(tree)
Expand Down Expand Up @@ -1077,7 +1081,7 @@ def _prompt_categorize(
f"[indirect]{child_snapshot.display_name(plan.environment_naming_info, default_catalog, dialect=self.dialect)}"
)
if indirect_tree:
indirect_tree = self._limit_model_names(indirect_tree, self.verbose)
indirect_tree = self._limit_model_names(indirect_tree, self.verbosity)

self._print(tree)
if not no_prompts:
Expand Down Expand Up @@ -1107,7 +1111,7 @@ def _show_categorized_snapshots(self, plan: Plan, default_catalog: t.Optional[st
f"[indirect]{child_snapshot.display_name(plan.environment_naming_info, default_catalog, dialect=self.dialect)} ({child_category_str})"
)
if indirect_tree:
indirect_tree = self._limit_model_names(indirect_tree, self.verbose)
indirect_tree = self._limit_model_names(indirect_tree, self.verbosity)
elif context_diff.metadata_updated(snapshot.name):
tree = Tree(
f"\n[bold][metadata]Metadata Updated: {snapshot.display_name(plan.environment_naming_info, default_catalog, dialect=self.dialect)}"
Expand Down Expand Up @@ -1144,7 +1148,7 @@ def _show_missing_dates(self, plan: Plan, default_catalog: t.Optional[str]) -> N
)

if backfill:
backfill = self._limit_model_names(backfill, self.verbose)
backfill = self._limit_model_names(backfill, self.verbosity)
self._print(backfill)

def _prompt_effective_from(
Expand Down Expand Up @@ -1993,7 +1997,10 @@ def show_model_difference_summary(
self._print("\n**Added Models:**")
added_models = sorted(added_snapshot_models)
list_length = len(added_models)
if not self.verbose and list_length > self.INDIRECTLY_MODIFIED_DISPLAY_THRESHOLD:
if (
self.verbosity < Verbosity.VERY_VERBOSE
and list_length > self.INDIRECTLY_MODIFIED_DISPLAY_THRESHOLD
):
self._print(added_models[0])
self._print(f"- `.... {list_length-2} more ....`\n")
self._print(added_models[-1])
Expand All @@ -2017,7 +2024,10 @@ def show_model_difference_summary(
self._print("\n**Removed Models:**")
removed_models = sorted(removed_model_snapshot_table_infos)
list_length = len(removed_models)
if not self.verbose and list_length > self.INDIRECTLY_MODIFIED_DISPLAY_THRESHOLD:
if (
self.verbosity < Verbosity.VERY_VERBOSE
and list_length > self.INDIRECTLY_MODIFIED_DISPLAY_THRESHOLD
):
self._print(removed_models[0])
self._print(f"- `.... {list_length-2} more ....`\n")
self._print(removed_models[-1])
Expand Down Expand Up @@ -2062,7 +2072,7 @@ def show_model_difference_summary(
indirectly_modified = sorted(indirectly_modified)
modified_length = len(indirectly_modified)
if (
not self.verbose
self.verbosity < Verbosity.VERY_VERBOSE
and modified_length > self.INDIRECTLY_MODIFIED_DISPLAY_THRESHOLD
):
self._print(
Expand Down Expand Up @@ -2106,7 +2116,10 @@ def _show_missing_dates(self, plan: Plan, default_catalog: t.Optional[str]) -> N
)

length = len(snapshots)
if not self.verbose and length > self.INDIRECTLY_MODIFIED_DISPLAY_THRESHOLD:
if (
self.verbosity < Verbosity.VERY_VERBOSE
and length > self.INDIRECTLY_MODIFIED_DISPLAY_THRESHOLD
):
self._print(snapshots[0])
self._print(f"- `.... {length-2} more ....`\n")
self._print(snapshots[-1])
Expand Down Expand Up @@ -2135,7 +2148,7 @@ def _show_categorized_snapshots(self, plan: Plan, default_catalog: t.Optional[st
f"[indirect]{child_snapshot.display_name(plan.environment_naming_info, default_catalog, dialect=self.dialect)} ({child_category_str})"
)
if indirect_tree:
indirect_tree = self._limit_model_names(indirect_tree, self.verbose)
indirect_tree = self._limit_model_names(indirect_tree, self.verbosity)
elif context_diff.metadata_updated(snapshot.name):
tree = Tree(
f"[bold][metadata]Metadata Updated: {snapshot.display_name(plan.environment_naming_info, default_catalog, dialect=self.dialect)}"
Expand Down Expand Up @@ -2364,7 +2377,7 @@ def __init__(
) -> None:
self.console: RichConsole = console or srich.console
self.dialect = dialect
self.verbose = False
self.verbosity = Verbosity.DEFAULT
self.ignore_warnings = ignore_warnings

def _write(self, msg: t.Any, *args: t.Any, **kwargs: t.Any) -> None:
Expand Down
21 changes: 11 additions & 10 deletions sqlmesh/core/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
run_tests,
)
from sqlmesh.core.user import User
from sqlmesh.utils import UniqueKeyDict
from sqlmesh.utils import UniqueKeyDict, Verbosity
from sqlmesh.utils.dag import DAG
from sqlmesh.utils.date import TimeLike, now_ds, to_timestamp, format_tz_datetime
from sqlmesh.utils.errors import (
Expand Down Expand Up @@ -1741,16 +1741,13 @@ def test(
self,
match_patterns: t.Optional[t.List[str]] = None,
tests: t.Optional[t.List[str]] = None,
verbose: bool = False,
verbosity: Verbosity = Verbosity.DEFAULT,
preserve_fixtures: bool = False,
stream: t.Optional[t.TextIO] = None,
) -> ModelTextTestResult:
"""Discover and run model tests"""
if verbose:
if verbosity >= Verbosity.VERBOSE:
pd.set_option("display.max_columns", None)
verbosity = 2
else:
verbosity = 1

if tests:
result = run_model_tests(
Expand Down Expand Up @@ -1954,15 +1951,17 @@ def create_external_models(self, strict: bool = False) -> None:
)

@python_api_analytics
def print_info(self, skip_connection: bool = False, verbose: bool = False) -> None:
def print_info(
self, skip_connection: bool = False, verbosity: Verbosity = Verbosity.DEFAULT
) -> None:
"""Prints information about connections, models, macros, etc. to the console."""
self.console.log_status_update(f"Models: {len(self.models)}")
self.console.log_status_update(f"Macros: {len(self._macros) - len(macro.get_registry())}")

if skip_connection:
return

if verbose:
if verbosity >= Verbosity.VERBOSE:
self.console.log_status_update("")
print_config(self.config.get_connection(self.gateway), self.console, "Connection")
print_config(
Expand Down Expand Up @@ -2072,9 +2071,11 @@ def clear_caches(self) -> None:
for path in self.configs:
rmtree(path / c.CACHE)

def _run_tests(self, verbose: bool = False) -> t.Tuple[unittest.result.TestResult, str]:
def _run_tests(
self, verbosity: Verbosity = Verbosity.DEFAULT
) -> t.Tuple[unittest.result.TestResult, str]:
test_output_io = StringIO()
result = self.test(stream=test_output_io, verbose=verbose)
result = self.test(stream=test_output_io, verbosity=verbosity)
return result, test_output_io.getvalue()

def _run_plan_tests(
Expand Down
10 changes: 6 additions & 4 deletions sqlmesh/core/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
load_model_test_file as load_model_test_file,
)
from sqlmesh.core.test.result import ModelTextTestResult as ModelTextTestResult
from sqlmesh.utils import UniqueKeyDict
from sqlmesh.utils import UniqueKeyDict, Verbosity

if t.TYPE_CHECKING:
from sqlmesh.core.config.loader import C
Expand All @@ -26,7 +26,7 @@ def run_tests(
config: C,
gateway: t.Optional[str] = None,
dialect: str | None = None,
verbosity: int = 1,
verbosity: Verbosity = Verbosity.DEFAULT,
preserve_fixtures: bool = False,
stream: t.TextIO | None = None,
default_catalog: str | None = None,
Expand Down Expand Up @@ -73,7 +73,9 @@ def run_tests(
result = t.cast(
ModelTextTestResult,
unittest.TextTestRunner(
stream=stream, verbosity=verbosity, resultclass=ModelTextTestResult
stream=stream,
verbosity=2 if verbosity >= Verbosity.VERBOSE else 1,
resultclass=ModelTextTestResult,
).run(unittest.TestSuite(tests)),
)
finally:
Expand All @@ -89,7 +91,7 @@ def run_model_tests(
config: C,
gateway: t.Optional[str] = None,
dialect: str | None = None,
verbosity: int = 1,
verbosity: Verbosity = Verbosity.DEFAULT,
patterns: list[str] | None = None,
preserve_fixtures: bool = False,
stream: t.TextIO | None = None,
Expand Down
4 changes: 2 additions & 2 deletions sqlmesh/integrations/github/cicd/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
)
from sqlmesh.core.user import User
from sqlmesh.integrations.github.cicd.config import GithubCICDBotConfig
from sqlmesh.utils import word_characters_only
from sqlmesh.utils import word_characters_only, Verbosity
from sqlmesh.utils.concurrency import NodeExecutionFailedError
from sqlmesh.utils.date import now
from sqlmesh.utils.errors import (
Expand Down Expand Up @@ -476,7 +476,7 @@ def run_tests(self) -> t.Tuple[unittest.result.TestResult, str]:
"""
Run tests for the PR
"""
return self._context._run_tests(verbose=True)
return self._context._run_tests(verbosity=Verbosity.VERBOSE)

def _get_or_create_comment(self, header: str = BOT_HEADER_MSG) -> IssueComment:
comment = seq_get(
Expand Down
Loading