run-cache 2.2.0__tar.gz → 2.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {run_cache-2.2.0 → run_cache-2.2.2}/PKG-INFO +3 -3
- run_cache-2.2.2/src/dbt_run_cache/_version.py +1 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/adapters/base.py +84 -31
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/adapters/snowflake.py +0 -27
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/cli/explainer.py +5 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/run_cache.py +5 -8
- run_cache-2.2.0/src/dbt_run_cache/_version.py +0 -1
- {run_cache-2.2.0 → run_cache-2.2.2}/.gitignore +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/pyproject.toml +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/__init__.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/_typing.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/adapters/__init__.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/adapters/bigquery.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/adapters/clock.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/adapters/common.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/adapters/databricks.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/adapters/postgres.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/auth/__init__.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/auth/grpc.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/auth/oauth_clients.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/auth/sso.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/auth/sso_server.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/auth/utils.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/cli/__init__.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/cli/auth.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/cli/main.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/config.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/decision_logger.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/dev_cloner.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/dispatcher.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/errors.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/events.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/git.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/grpc/__init__.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/grpc/client.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/grpc/interceptors.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/plugin.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/profiles.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/relation.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/runner.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/selector.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/session.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/system_info.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/utils.py +0 -0
- {run_cache-2.2.0 → run_cache-2.2.2}/src/dbt_run_cache/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: run-cache
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: dbt plugin that skips redundant model executions by caching results from previous runs
|
|
5
5
|
Project-URL: Homepage, https://runcache.com
|
|
6
6
|
License: Copyright (c) 2026 Fivetran, Inc.
|
|
@@ -46,8 +46,8 @@ Requires-Dist: humanize
|
|
|
46
46
|
Requires-Dist: protobuf>=4.0.0
|
|
47
47
|
Requires-Dist: pyperclip
|
|
48
48
|
Requires-Dist: pytimeparse2
|
|
49
|
-
Requires-Dist: query-cache-common==1.
|
|
50
|
-
Requires-Dist: query-cache-protobuf==1.
|
|
49
|
+
Requires-Dist: query-cache-common==1.4.0
|
|
50
|
+
Requires-Dist: query-cache-protobuf==1.3.0
|
|
51
51
|
Requires-Dist: rich
|
|
52
52
|
Requires-Dist: ruamel-yaml
|
|
53
53
|
Requires-Dist: sqlglot>=27.6.1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.2.2"
|
|
@@ -37,6 +37,7 @@ from dbt_run_cache.utils import find_tables
|
|
|
37
37
|
|
|
38
38
|
if t.TYPE_CHECKING:
|
|
39
39
|
from dbt.contracts.graph.nodes import ManifestNode
|
|
40
|
+
from dbt.contracts.graph.manifest import SourceDefinition
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
class BaseAdapterExtension(abc.ABC):
|
|
@@ -146,11 +147,6 @@ class BaseAdapterExtension(abc.ABC):
|
|
|
146
147
|
def rollback(self) -> None:
|
|
147
148
|
self.adapter.connections.rollback_if_open()
|
|
148
149
|
|
|
149
|
-
def table_(
|
|
150
|
-
self, table: str, schema: t.Optional[str], catalog: t.Optional[str], quoted: bool = True
|
|
151
|
-
) -> exp.Table:
|
|
152
|
-
return exp.table_(table, db=schema, catalog=catalog, quoted=quoted)
|
|
153
|
-
|
|
154
150
|
def get_last_modified_epoch(
|
|
155
151
|
self, tables: t.Iterable[str | exp.Table]
|
|
156
152
|
) -> dict[str, t.Optional[int]]:
|
|
@@ -470,7 +466,7 @@ class BaseAdapterExtension(abc.ABC):
|
|
|
470
466
|
This is for when the plugin creates new database objects after dbt has populated its relation cache, to ensure those
|
|
471
467
|
objects are reflected / available to the remainder of the dbt invocation.
|
|
472
468
|
"""
|
|
473
|
-
relation = self.
|
|
469
|
+
relation = self._node_to_relation(node)
|
|
474
470
|
self.adapter.cache_added(relation)
|
|
475
471
|
|
|
476
472
|
def relation_exists(self, relation: BaseRelation) -> bool:
|
|
@@ -519,24 +515,79 @@ class BaseAdapterExtension(abc.ABC):
|
|
|
519
515
|
|
|
520
516
|
return data
|
|
521
517
|
|
|
522
|
-
def
|
|
523
|
-
|
|
524
|
-
|
|
518
|
+
def _node_to_normalized_identifiers(
|
|
519
|
+
self,
|
|
520
|
+
node: ManifestNode | SourceDefinition,
|
|
521
|
+
override_database: t.Optional[str] = None,
|
|
522
|
+
override_schema: t.Optional[str] = None,
|
|
523
|
+
) -> t.Tuple[str, str, str, t.Dict[str, bool]]:
|
|
524
|
+
"""Break a dbt manifest node into parts that can be force-quoted without first normalizing.
|
|
525
|
+
|
|
526
|
+
dbt supports quoting the catalog, schema and identifier portions independently whereas SQLGlot
|
|
527
|
+
tends to be all-or-none.
|
|
528
|
+
|
|
529
|
+
The output of this method can be used to construct both dbt Relation objects and SQLGlot exp.Table objects
|
|
530
|
+
that are consistent with each other.
|
|
531
|
+
|
|
532
|
+
:override_database and :override_schema can be used to override the values used for the database and schema portions without
|
|
533
|
+
changing the input node object
|
|
534
|
+
|
|
535
|
+
Returns a tuple of (database, schema, identifier, quote_policy). These are deliberately strings so that they can be used to construct
|
|
536
|
+
a Relation object, but they have been normalized according to the quote policy
|
|
537
|
+
"""
|
|
538
|
+
quote_policy = {
|
|
539
|
+
**self.adapter.Relation.get_default_quote_policy().to_dict(omit_none=True),
|
|
540
|
+
**self.adapter.config.quoting,
|
|
541
|
+
**node.config.get("quoting", {}),
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
database = override_database or node.database or self.default_catalog
|
|
545
|
+
schema = override_schema or node.schema
|
|
546
|
+
identifier = str(node.alias if hasattr(node, "alias") else node.identifier)
|
|
547
|
+
|
|
548
|
+
# normalize any unquoted identifiers
|
|
549
|
+
if not quote_policy["database"] and database:
|
|
550
|
+
database = self._sql(self._normalize_identifier(database))
|
|
551
|
+
|
|
552
|
+
if not quote_policy["schema"] and schema:
|
|
553
|
+
schema = self._sql(self._normalize_identifier(schema))
|
|
554
|
+
|
|
555
|
+
if not quote_policy["identifier"] and identifier:
|
|
556
|
+
identifier = self._sql(self._normalize_identifier(identifier))
|
|
557
|
+
|
|
558
|
+
return database, schema, identifier, quote_policy
|
|
525
559
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
)
|
|
531
|
-
quoting_policy.update(policy)
|
|
560
|
+
def _node_to_relation(self, node: ManifestNode | SourceDefinition) -> BaseRelation:
|
|
561
|
+
"""Turn a dbt manifest node into an adapter-specific Relation object suitable for putting
|
|
562
|
+
into the Relation cache, while respecting the configured quote policy"""
|
|
563
|
+
|
|
564
|
+
database, schema, identifier, dbt_quote_policy = self._node_to_normalized_identifiers(node)
|
|
532
565
|
|
|
533
566
|
return self.adapter.Relation.create(
|
|
534
|
-
database=
|
|
535
|
-
schema=
|
|
536
|
-
identifier=
|
|
567
|
+
database=database,
|
|
568
|
+
schema=schema,
|
|
569
|
+
identifier=identifier,
|
|
537
570
|
type=RelationType.Table,
|
|
538
|
-
|
|
571
|
+
quote_policy=dbt_quote_policy,
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
def _node_to_table(
|
|
575
|
+
self,
|
|
576
|
+
node: ManifestNode | SourceDefinition,
|
|
577
|
+
override_database: t.Optional[str] = None,
|
|
578
|
+
override_schema: t.Optional[str] = None,
|
|
579
|
+
) -> exp.Table:
|
|
580
|
+
"""Given a dbt node, convert it to a SQLGlot exp.Table object while applying correct quoting
|
|
581
|
+
and normalization per the dbt quote policy for this node.
|
|
582
|
+
|
|
583
|
+
Note that since dbt allows a mixture of quoted and unquoted parts and SQLGlot prefers all or nothing,
|
|
584
|
+
the produced SQLGlot exp.Table is semantically equivalent but not identical to the dbt Node.
|
|
585
|
+
This is achieved by normalizing any identifiers that are unquoted on the dbt side and then force-quoting everything
|
|
586
|
+
"""
|
|
587
|
+
database, schema, identifier, _ = self._node_to_normalized_identifiers(
|
|
588
|
+
node, override_database=override_database, override_schema=override_schema
|
|
539
589
|
)
|
|
590
|
+
return exp.table_(catalog=database, db=schema, table=identifier, quoted=True)
|
|
540
591
|
|
|
541
592
|
def get_relation_table_type(
|
|
542
593
|
self, node: ManifestNode, relation: BaseRelation
|
|
@@ -701,12 +752,16 @@ class BaseAdapterExtension(abc.ABC):
|
|
|
701
752
|
# since _to_fqn() returns the table parts quoted, we have to normalize unquoted identifiers first
|
|
702
753
|
# if we force-quote without normalizing then on engines like Snowflake we end up with identifiers
|
|
703
754
|
# that should be uppercase stuck as lowercase because they were force-quoted
|
|
704
|
-
return
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
755
|
+
return quote_identifiers(
|
|
756
|
+
normalize_identifiers(
|
|
757
|
+
exp.table_(
|
|
758
|
+
table_name,
|
|
759
|
+
db=table_schema,
|
|
760
|
+
catalog=table_catalog,
|
|
761
|
+
),
|
|
762
|
+
dialect=self.dialect,
|
|
763
|
+
),
|
|
764
|
+
dialect=self.dialect,
|
|
710
765
|
)
|
|
711
766
|
|
|
712
767
|
def _sql(self, expression: exp.Expr, copy: bool = False) -> str:
|
|
@@ -718,12 +773,10 @@ class BaseAdapterExtension(abc.ABC):
|
|
|
718
773
|
"""
|
|
719
774
|
return expression.sql(dialect=self.dialect, copy=copy)
|
|
720
775
|
|
|
721
|
-
def
|
|
722
|
-
if isinstance(
|
|
723
|
-
|
|
724
|
-
return
|
|
725
|
-
normalize_identifiers(table, dialect=self.dialect), dialect=self.dialect
|
|
726
|
-
)
|
|
776
|
+
def _normalize_identifier(self, expr: t.Union[str, exp.Identifier]) -> exp.Identifier:
|
|
777
|
+
if isinstance(expr, str):
|
|
778
|
+
expr = exp.parse_identifier(expr, dialect=self.dialect)
|
|
779
|
+
return normalize_identifiers(expr, dialect=self.dialect)
|
|
727
780
|
|
|
728
781
|
def _is_system_metadata_table(self, table: exp.Table) -> bool:
|
|
729
782
|
"""Is the specified table a known system metadata table/view?
|
|
@@ -18,11 +18,6 @@ from dbt_run_cache.utils import set_invocation_context
|
|
|
18
18
|
from query_cache_common.utils import extract_fqn_parts
|
|
19
19
|
import re
|
|
20
20
|
|
|
21
|
-
try:
|
|
22
|
-
from dbt.adapters.contracts.relation import RelationType
|
|
23
|
-
except ImportError:
|
|
24
|
-
# dbt 1.7
|
|
25
|
-
from dbt.adapters.base.relation import RelationType
|
|
26
21
|
|
|
27
22
|
if t.TYPE_CHECKING:
|
|
28
23
|
from dbt.contracts.graph.nodes import ManifestNode
|
|
@@ -44,28 +39,6 @@ class SnowflakeAdapterExtension(BaseAdapterExtension):
|
|
|
44
39
|
def current_timestamp_utc(self) -> datetime:
|
|
45
40
|
return self.execute("SELECT SYSDATE()", fetch=True).rows[0][0].replace(tzinfo=timezone.utc)
|
|
46
41
|
|
|
47
|
-
def _create_cachable_relation(self, node: ManifestNode) -> BaseRelation:
|
|
48
|
-
from dbt.adapters.snowflake.relation import SnowflakeRelation
|
|
49
|
-
|
|
50
|
-
# when building its relation cache, the Snowflake adapter:
|
|
51
|
-
# - caches what it gets from Snowflake's INFORMATION_SCHEMA, which is usually uppercase
|
|
52
|
-
# - hardcodes the below quoting policy
|
|
53
|
-
# so if we are writing our own relations into the cache, we need to normalize them, or we get an ApproximateMatchError when trying to read them back
|
|
54
|
-
# ref: https://github.com/dbt-labs/dbt-adapters/blob/60fc903f705f447a7b58d0df6b33d7be7cd00690/dbt-snowflake/src/dbt/adapters/snowflake/impl.py#L321
|
|
55
|
-
quoting_policy = {"database": True, "schema": True, "identifier": True}
|
|
56
|
-
|
|
57
|
-
normalized = self._normalize_and_quote_table(
|
|
58
|
-
self.table_(catalog=node.database, schema=node.schema, table=node.alias, quoted=False)
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
return SnowflakeRelation.create(
|
|
62
|
-
database=normalized.catalog,
|
|
63
|
-
schema=normalized.db,
|
|
64
|
-
identifier=normalized.name,
|
|
65
|
-
type=RelationType.Table,
|
|
66
|
-
quoting_policy=quoting_policy,
|
|
67
|
-
)
|
|
68
|
-
|
|
69
42
|
def get_relation_table_type(
|
|
70
43
|
self, node: ManifestNode, relation: BaseRelation
|
|
71
44
|
) -> t.Optional[str]:
|
|
@@ -106,6 +106,11 @@ class Explainer:
|
|
|
106
106
|
for log_entry in no_decision_entries:
|
|
107
107
|
self._explain_no_decision_node(log_entry)
|
|
108
108
|
|
|
109
|
+
def explain_to_str(self) -> str:
|
|
110
|
+
with self._console.capture() as capture:
|
|
111
|
+
self.explain()
|
|
112
|
+
return capture.get()
|
|
113
|
+
|
|
109
114
|
def _explain_run_start(self, run_start_entry: RunStartEntry) -> None:
|
|
110
115
|
self._print("Last run: ")
|
|
111
116
|
|
|
@@ -1132,19 +1132,16 @@ class RunCache:
|
|
|
1132
1132
|
return last_modified_epoch
|
|
1133
1133
|
|
|
1134
1134
|
def _node_to_table(self, node: ManifestNode | SourceDefinition) -> exp.Table:
|
|
1135
|
-
|
|
1136
|
-
schema = node.schema
|
|
1137
|
-
table_name = t.cast(str, node.alias if hasattr(node, "alias") else node.identifier)
|
|
1138
|
-
table = self._adapter_ext.table_(table_name, schema, database, quoted=False)
|
|
1139
|
-
return self._adapter_ext._normalize_and_quote_table(table)
|
|
1135
|
+
return self._adapter_ext._node_to_table(node)
|
|
1140
1136
|
|
|
1141
1137
|
def _node_to_deferred_table(self, node: ManifestNode) -> exp.Table:
|
|
1142
1138
|
assert self._deferred_relation_resolver is not None
|
|
1143
1139
|
database = self._deferred_relation_resolver.get_deferred_database(node) or node.database
|
|
1144
1140
|
schema = self._deferred_relation_resolver.get_deferred_schema(node) or node.schema
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1141
|
+
|
|
1142
|
+
return self._adapter_ext._node_to_table(
|
|
1143
|
+
node, override_database=database, override_schema=schema
|
|
1144
|
+
)
|
|
1148
1145
|
|
|
1149
1146
|
def _record_cache_hit(
|
|
1150
1147
|
self,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.2.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|