-
Notifications
You must be signed in to change notification settings - Fork 380
execution context fixes #20 #34
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
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
1f76d48
execution context fixes #20
tobymao 3059f79
Update sqlmesh/core/context.py
tobymao 2d4c701
Update sqlmesh/core/context.py
tobymao 24dbe57
Update sqlmesh/core/model.py
tobymao 23a929b
Update sqlmesh/core/model.py
tobymao 7fbf430
pr review
tobymao 37c0b77
Merge branch 'main' into toby/execution_context
tobymao File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,7 @@ | |
| """ | ||
| from __future__ import annotations | ||
|
|
||
| import abc | ||
| import contextlib | ||
| import importlib | ||
| import types | ||
|
|
@@ -50,7 +51,7 @@ | |
| from sqlmesh.core.context_diff import ContextDiff | ||
| from sqlmesh.core.dag import DAG | ||
| from sqlmesh.core.dialect import extend_sqlglot, format_model_expressions | ||
| from sqlmesh.core.engine_adapter import EngineAdapter | ||
| from sqlmesh.core.engine_adapter import DF, EngineAdapter | ||
| from sqlmesh.core.environment import Environment | ||
| from sqlmesh.core.macros import macro | ||
| from sqlmesh.core.model import Model | ||
|
|
@@ -69,10 +70,76 @@ | |
| if t.TYPE_CHECKING: | ||
| import graphviz | ||
|
|
||
| MODEL_OR_SNAPSHOT = t.Union[str, Model, Snapshot] | ||
|
|
||
| extend_sqlglot() | ||
|
|
||
|
|
||
| class Context: | ||
| class BaseContext(abc.ABC): | ||
| """The base context which defines methods to execute a model.""" | ||
|
|
||
| @property | ||
| @abc.abstractmethod | ||
| def model_tables(self) -> t.Dict[str, str]: | ||
| """Returns a mapping of model names to tables.""" | ||
|
|
||
| @property | ||
| @abc.abstractmethod | ||
| def engine_adapter(self) -> EngineAdapter: | ||
| """Returns an engine adapter.""" | ||
|
|
||
| @property | ||
| def spark(self) -> t.Optional["pyspark.sql.SparkSession"]: # type: ignore | ||
| """Returns the spark session if it exists.""" | ||
| return self.engine_adapter.spark | ||
|
|
||
| def table(self, model_name: str) -> str: | ||
| """Gets the physical table name for a given model. | ||
|
|
||
| Args: | ||
| model_name: The model name. | ||
|
|
||
| Returns: | ||
| The physical table name. | ||
| """ | ||
| return self.model_tables[model_name] | ||
|
|
||
| def fetchdf(self, query: t.Union[exp.Expression, str]) -> DF: | ||
| """Fetches a dataframe given a sql string or sqlglot expression. | ||
|
|
||
| Args: | ||
| query: SQL string or sqlglot expression. | ||
|
|
||
| Returns: | ||
| The default dataframe is Pandas, but for Spark a PySpark dataframe is returned. | ||
| """ | ||
| return self.engine_adapter.fetchdf(query) | ||
|
|
||
|
|
||
| class ExecutionContext(BaseContext): | ||
| """The minimal context needed to execute a model. | ||
|
|
||
| Args: | ||
| engine_adapter: The engine adapter to execute queries against. | ||
| mapping: A mapping of models to physical tables. | ||
| """ | ||
|
|
||
| def __init__(self, engine_adapter: EngineAdapter, model_tables: t.Dict[str, str]): | ||
| self._engine_adapter = engine_adapter | ||
| self._model_tables = model_tables | ||
|
|
||
| @property | ||
| def engine_adapter(self) -> EngineAdapter: | ||
| """Returns an engine adapter.""" | ||
| return self._engine_adapter | ||
|
|
||
| @property | ||
| def model_tables(self) -> t.Dict[str, str]: | ||
| """Returns a mapping of model names to tables.""" | ||
| return self._model_tables | ||
|
|
||
|
|
||
| class Context(BaseContext): | ||
| """Encapsulates a SQLMesh environment supplying convenient functions to perform various tasks. | ||
|
|
||
| Args: | ||
|
|
@@ -137,7 +204,7 @@ def __init__( | |
| ddl_concurrent_tasks or self.config.ddl_concurrent_tasks | ||
| ) | ||
|
|
||
| self.engine_adapter = engine_adapter or EngineAdapter( | ||
| self._engine_adapter = engine_adapter or EngineAdapter( | ||
| self.config.engine_connection_factory, | ||
| self.config.engine_dialect, | ||
| multithreaded=self.ddl_concurrent_tasks > 1, | ||
|
|
@@ -170,6 +237,11 @@ def __init__( | |
| if load: | ||
| self.load() | ||
|
|
||
| @property | ||
| def engine_adapter(self) -> EngineAdapter: | ||
| """Returns an engine adapter.""" | ||
| return self._engine_adapter | ||
|
|
||
| def upsert_model(self, model: t.Union[str, Model] = "", **kwargs) -> Model: | ||
| """Update or insert a model. | ||
|
|
||
|
|
@@ -303,9 +375,22 @@ def snapshots(self) -> t.Dict[str, Snapshot]: | |
| snapshots[model.name] = snapshot | ||
| return snapshots | ||
|
|
||
| @property | ||
| def model_tables(self) -> t.Dict[str, str]: | ||
| """Mapping of model name to physical table name. | ||
|
|
||
| If a snapshot has not been versioned yet, its view name will be returned. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why return view? So that local evaluation works?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea, in case you haven't pushed a snapshot yet (because you can run evaluate before plan) |
||
| """ | ||
| return { | ||
| name: snapshot.table_name | ||
| if snapshot.version | ||
| else snapshot.qualified_view_name.for_environment(c.PROD) | ||
| for name, snapshot in self.snapshots.items() | ||
| } | ||
|
|
||
| def render( | ||
| self, | ||
| model: t.Union[str, Model], | ||
| model_or_snapshot: MODEL_OR_SNAPSHOT, | ||
| *, | ||
| start: t.Optional[TimeLike] = None, | ||
| end: t.Optional[TimeLike] = None, | ||
|
|
@@ -317,7 +402,7 @@ def render( | |
| """Renders a model's query, expanding macros with provided kwargs, and optionally expanding referenced models. | ||
|
|
||
| Args: | ||
| model: The model name or instance to render. | ||
| model_or_snapshot: The model, model name, or snapshot to render. | ||
| start: The start of the interval to render. | ||
| end: The end of the interval to render. | ||
| latest: The latest time used for non incremental datasets. | ||
|
|
@@ -330,7 +415,14 @@ def render( | |
| The rendered expression. | ||
| """ | ||
| latest = latest or yesterday_ds() | ||
| model = model if isinstance(model, Model) else self.models[model] | ||
|
|
||
| if isinstance(model_or_snapshot, str): | ||
| model = self.models[model_or_snapshot] | ||
| elif isinstance(model_or_snapshot, Snapshot): | ||
| model = model_or_snapshot.model | ||
| else: | ||
| model = model_or_snapshot | ||
|
|
||
| expand = self.dag.upstream(model.name) if expand is True else expand or [] | ||
|
|
||
| return model.render_query( | ||
|
|
@@ -345,33 +437,43 @@ def render( | |
|
|
||
| def evaluate( | ||
| self, | ||
| snapshot: Snapshot | str, | ||
| model_or_snapshot: MODEL_OR_SNAPSHOT, | ||
| start: TimeLike, | ||
| end: TimeLike, | ||
| latest: TimeLike, | ||
| limit: t.Optional[int] = None, | ||
| **kwargs, | ||
| ) -> None: | ||
| """Evaluate a snapshot (running its query against a DB/Engine). | ||
| ) -> DF: | ||
| """Evaluate a model or snapshot (running its query against a DB/Engine). | ||
|
|
||
| This method is used to test or iterate on models without side effects. | ||
|
|
||
| Args: | ||
| snapshot: The snapshot to evaluate. | ||
| model_or_snapshot: The model, model name, or snapshot to render. | ||
| start: The start of the interval to evaluate. | ||
| end: The end of the interval to evaluate. | ||
| latest: The latest time used for non incremental datasets. | ||
| limit: A limit applied to the model, this must be > 0. | ||
| """ | ||
| if isinstance(snapshot, str): | ||
| snapshot = self.snapshots[snapshot] | ||
| if isinstance(model_or_snapshot, str): | ||
| snapshot = self.snapshots[model_or_snapshot] | ||
| elif isinstance(model_or_snapshot, Model): | ||
| snapshot = self.snapshots[model_or_snapshot.name] | ||
| else: | ||
| snapshot = model_or_snapshot | ||
|
|
||
| if not limit or limit <= 0: | ||
| limit = 1000 | ||
|
|
||
| self.snapshot_evaluator.evaluate( | ||
| return self.snapshot_evaluator.evaluate( | ||
| snapshot, | ||
| start, | ||
| end, | ||
| latest, | ||
| snapshots=self.snapshots, | ||
| mapping=self.model_tables, | ||
| limit=limit, | ||
| ) | ||
|
|
||
| self.state_sync.add_interval(snapshot.snapshot_id, start, end) | ||
|
|
||
| def format(self) -> None: | ||
| """Format all models in a given directory.""" | ||
| for model in self.models.values(): | ||
|
|
@@ -680,7 +782,11 @@ def _load_models(self): | |
| new = registry.keys() - registered | ||
| registered |= new | ||
| for name in new: | ||
| model = registry[name].model(module, path) | ||
| model = registry[name].model( | ||
| module=module, | ||
| path=path, | ||
| time_column_format=self.config.time_column_format, | ||
| ) | ||
| self.models[model.name] = model | ||
| self._add_model_to_dag(model) | ||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.