run-cache 2.2.2__tar.gz → 2.3.1__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.
Files changed (45) hide show
  1. {run_cache-2.2.2 → run_cache-2.3.1}/PKG-INFO +3 -3
  2. run_cache-2.3.1/src/dbt_run_cache/_version.py +1 -0
  3. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/adapters/base.py +6 -0
  4. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/adapters/bigquery.py +1 -0
  5. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/adapters/databricks.py +2 -0
  6. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/grpc/client.py +6 -7
  7. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/run_cache.py +24 -1
  8. run_cache-2.2.2/src/dbt_run_cache/_version.py +0 -1
  9. {run_cache-2.2.2 → run_cache-2.3.1}/.gitignore +0 -0
  10. {run_cache-2.2.2 → run_cache-2.3.1}/pyproject.toml +0 -0
  11. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/__init__.py +0 -0
  12. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/_typing.py +0 -0
  13. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/adapters/__init__.py +0 -0
  14. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/adapters/clock.py +0 -0
  15. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/adapters/common.py +0 -0
  16. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/adapters/postgres.py +0 -0
  17. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/adapters/snowflake.py +0 -0
  18. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/auth/__init__.py +0 -0
  19. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/auth/grpc.py +0 -0
  20. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/auth/oauth_clients.py +0 -0
  21. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/auth/sso.py +0 -0
  22. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/auth/sso_server.py +0 -0
  23. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/auth/utils.py +0 -0
  24. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/cli/__init__.py +0 -0
  25. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/cli/auth.py +0 -0
  26. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/cli/explainer.py +0 -0
  27. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/cli/main.py +0 -0
  28. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/config.py +0 -0
  29. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/decision_logger.py +0 -0
  30. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/dev_cloner.py +0 -0
  31. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/dispatcher.py +0 -0
  32. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/errors.py +0 -0
  33. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/events.py +0 -0
  34. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/git.py +0 -0
  35. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/grpc/__init__.py +0 -0
  36. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/grpc/interceptors.py +0 -0
  37. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/plugin.py +0 -0
  38. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/profiles.py +0 -0
  39. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/relation.py +0 -0
  40. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/runner.py +0 -0
  41. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/selector.py +0 -0
  42. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/session.py +0 -0
  43. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/system_info.py +0 -0
  44. {run_cache-2.2.2 → run_cache-2.3.1}/src/dbt_run_cache/utils.py +0 -0
  45. {run_cache-2.2.2 → run_cache-2.3.1}/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.2
3
+ Version: 2.3.1
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.4.0
50
- Requires-Dist: query-cache-protobuf==1.3.0
49
+ Requires-Dist: query-cache-common==1.5.0
50
+ Requires-Dist: query-cache-protobuf==1.4.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.3.1"
@@ -53,6 +53,12 @@ class BaseAdapterExtension(abc.ABC):
53
53
  SYSTEM_METADATA_SCHEMAS: t.List[str] = ["information_schema"]
54
54
  """Schemas that should not have their last modified / view definition tracked"""
55
55
 
56
+ CLONE_CHAIN_DEPTH_LIMIT: t.Optional[int] = None
57
+ """How many clones of clones can be created before the database throws a "Cannot have more than N chained clones"-style error.
58
+ 0 = cloning effectively disabled
59
+ None = no limit imposed
60
+ """
61
+
56
62
  _CONNECTION_BARRIER_TIMEOUT_SECONDS: float = 2.0
57
63
 
58
64
  def __init__(
@@ -17,6 +17,7 @@ if t.TYPE_CHECKING:
17
17
 
18
18
  class BigQueryAdapterExtension(BaseAdapterExtension):
19
19
  REQUIRES_NAMED_CONNECTION = False
20
+ CLONE_CHAIN_DEPTH_LIMIT = 3
20
21
 
21
22
  def __init__(self, *args: t.Any, **kwargs: t.Any) -> None:
22
23
  super().__init__(*args, **kwargs)
@@ -33,6 +33,8 @@ def contains_unqualified_table_references(query: exp.Expr) -> bool:
33
33
 
34
34
 
35
35
  class DatabricksAdapterExtension(BaseAdapterExtension):
36
+ CLONE_CHAIN_DEPTH_LIMIT = 1
37
+
36
38
  def _fetch_last_modified_epochs(
37
39
  self, table_batch: t.Collection[exp.Table]
38
40
  ) -> t.Dict[str, t.Optional[int]]:
@@ -262,15 +262,15 @@ class QueryCacheGrpcClient:
262
262
  def register_clone(
263
263
  self, request: clone_service_models.CloneRequest
264
264
  ) -> t.Union[
265
- clone_service_models.ReadyToCloneResponse, clone_service_models.UntrackableCloneResponse
265
+ clone_service_models.ReadyToCloneResponse, clone_service_models.UnableToCloneResponse
266
266
  ]:
267
- """Register a clone table request.
267
+ """Attempts to register a clone table request.
268
268
 
269
269
  Args:
270
270
  request: CloneRequest with clone details
271
271
 
272
272
  Returns:
273
- Either ReadyToCloneResponse or UntrackableCloneResponse
273
+ Either ReadyToCloneResponse or UnableToCloneResponse
274
274
 
275
275
  Raises:
276
276
  grpc.RpcError: If the RPC fails
@@ -282,15 +282,14 @@ class QueryCacheGrpcClient:
282
282
  # Can remove has field check once old services are deprecated
283
283
  if response.HasField("ready_to_clone"):
284
284
  return clone_service_models.ReadyToCloneResponse.from_proto(response.ready_to_clone)
285
+ if response.HasField("unable_to_clone"):
286
+ return clone_service_models.UnableToCloneResponse.from_proto(response.unable_to_clone)
285
287
 
286
288
  # Extract the actual response from the oneof wrapper
287
289
  which = response.WhichOneof("response")
288
290
  if which == "ready_to_clone_v1":
289
291
  return clone_service_models.ReadyToCloneResponse.from_proto(response.ready_to_clone_v1)
290
- if which == "untrackable_clone":
291
- return clone_service_models.UntrackableCloneResponse.from_proto(
292
- response.untrackable_clone
293
- )
292
+
294
293
  raise ValueError(f"Unexpected response type: {which}")
295
294
 
296
295
  def confirm_execution(self, request: execution_service_models.ConfirmExecutionRequest) -> None:
@@ -698,6 +698,14 @@ class RunCache:
698
698
  clone_response = self._submit_clone_request(node)
699
699
  if clone_response is None:
700
700
  return False
701
+
702
+ if isinstance(clone_response, clone_service_models.UnableToCloneResponse):
703
+ clone_rejection_reason = clone_response.explained_decision.clone_rejection_reason
704
+ events.fire_debug_event(
705
+ f"Unable to clone {clone_response.clone_source}: {clone_rejection_reason}"
706
+ )
707
+ return False
708
+
701
709
  self._dev_cloner.clone(
702
710
  self._adapter,
703
711
  node,
@@ -844,6 +852,7 @@ class RunCache:
844
852
  labels=self._get_request_labels(node),
845
853
  clone_time_travel_limit=self._clone_time_travel_limit,
846
854
  clone_table_properties=self._get_table_properties(node),
855
+ clone_chain_depth_limit=self.clone_chain_depth_limit,
847
856
  )
848
857
 
849
858
  def _emit_enriched_sql_prepared_telemetry(
@@ -917,7 +926,7 @@ class RunCache:
917
926
  self, node: ModelOrSnapshotNode
918
927
  ) -> t.Optional[
919
928
  t.Union[
920
- clone_service_models.ReadyToCloneResponse, clone_service_models.UntrackableCloneResponse
929
+ clone_service_models.ReadyToCloneResponse, clone_service_models.UnableToCloneResponse
921
930
  ]
922
931
  ]:
923
932
  assert self._dev_cloner is not None
@@ -977,6 +986,7 @@ class RunCache:
977
986
  labels=self._get_request_labels(node),
978
987
  clone_time_travel_limit=self._clone_time_travel_limit,
979
988
  clone_table_properties=self._get_table_properties(node),
989
+ clone_chain_depth_limit=self.clone_chain_depth_limit,
980
990
  ), EnrichmentTimings(last_modified_duration_ms=last_modified_duration_ms)
981
991
 
982
992
  view_traversal_start = perf_counter()
@@ -1035,6 +1045,7 @@ class RunCache:
1035
1045
  labels=self._get_request_labels(node),
1036
1046
  clone_time_travel_limit=self._clone_time_travel_limit,
1037
1047
  clone_table_properties=self._get_table_properties(node),
1048
+ clone_chain_depth_limit=self.clone_chain_depth_limit,
1038
1049
  ), EnrichmentTimings(
1039
1050
  view_traversal_duration_ms=view_traversal_duration_ms,
1040
1051
  last_modified_duration_ms=last_modified_duration_ms,
@@ -1059,6 +1070,7 @@ class RunCache:
1059
1070
  labels=self._get_request_labels(node),
1060
1071
  clone_source_table_type=clone_source_table_type,
1061
1072
  table_properties=self._get_table_properties(node),
1073
+ clone_chain_depth_limit=self.clone_chain_depth_limit,
1062
1074
  )
1063
1075
 
1064
1076
  @staticmethod
@@ -1234,6 +1246,17 @@ class RunCache:
1234
1246
  def total_time_saved_ms(self) -> int:
1235
1247
  return self._total_time_saved_ms
1236
1248
 
1249
+ @property
1250
+ def clone_chain_depth_limit(self) -> t.Optional[int]:
1251
+ default_limit = self._adapter_ext.CLONE_CHAIN_DEPTH_LIMIT
1252
+
1253
+ # in prod, we set 1 less than the actual limit (which may force an execute instead of a clone)
1254
+ # this ensures that there is always at least 1 more clone left for a dev clone
1255
+ if self._defer_enabled and self._profiles.is_defer_to_profile and default_limit is not None:
1256
+ return max(default_limit - 1, 0)
1257
+
1258
+ return default_limit
1259
+
1237
1260
 
1238
1261
  class _DataTestAdapterProxy:
1239
1262
  def __init__(
@@ -1 +0,0 @@
1
- __version__ = "2.2.2"
File without changes
File without changes