sqlmesh 0.186.2.dev11__py3-none-any.whl → 0.186.2.dev13__py3-none-any.whl
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.
- sqlmesh/_version.py +2 -2
- sqlmesh/core/loader.py +195 -80
- sqlmesh/core/model/cache.py +17 -11
- sqlmesh/core/model/schema.py +15 -32
- sqlmesh/core/snapshot/cache.py +13 -14
- sqlmesh/dbt/loader.py +13 -0
- sqlmesh/utils/concurrency.py +14 -7
- sqlmesh/utils/process.py +73 -0
- {sqlmesh-0.186.2.dev11.dist-info → sqlmesh-0.186.2.dev13.dist-info}/METADATA +1 -1
- {sqlmesh-0.186.2.dev11.dist-info → sqlmesh-0.186.2.dev13.dist-info}/RECORD +14 -13
- {sqlmesh-0.186.2.dev11.dist-info → sqlmesh-0.186.2.dev13.dist-info}/WHEEL +0 -0
- {sqlmesh-0.186.2.dev11.dist-info → sqlmesh-0.186.2.dev13.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.186.2.dev11.dist-info → sqlmesh-0.186.2.dev13.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.186.2.dev11.dist-info → sqlmesh-0.186.2.dev13.dist-info}/top_level.txt +0 -0
sqlmesh/_version.py
CHANGED
|
@@ -17,5 +17,5 @@ __version__: str
|
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
|
18
18
|
version_tuple: VERSION_TUPLE
|
|
19
19
|
|
|
20
|
-
__version__ = version = '0.186.2.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 186, 2, '
|
|
20
|
+
__version__ = version = '0.186.2.dev13'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 186, 2, 'dev13')
|
sqlmesh/core/loader.py
CHANGED
|
@@ -4,7 +4,6 @@ import abc
|
|
|
4
4
|
import glob
|
|
5
5
|
import itertools
|
|
6
6
|
import linecache
|
|
7
|
-
import logging
|
|
8
7
|
import os
|
|
9
8
|
import re
|
|
10
9
|
import typing as t
|
|
@@ -12,6 +11,7 @@ from collections import Counter, defaultdict
|
|
|
12
11
|
from dataclasses import dataclass
|
|
13
12
|
from pathlib import Path
|
|
14
13
|
from pydantic import ValidationError
|
|
14
|
+
import concurrent.futures
|
|
15
15
|
|
|
16
16
|
from sqlglot.errors import SqlglotError
|
|
17
17
|
from sqlglot import exp
|
|
@@ -19,6 +19,7 @@ from sqlglot.helper import subclasses
|
|
|
19
19
|
|
|
20
20
|
from sqlmesh.core import constants as c
|
|
21
21
|
from sqlmesh.core.audit import Audit, ModelAudit, StandaloneAudit, load_multiple_audits
|
|
22
|
+
from sqlmesh.core.console import Console
|
|
22
23
|
from sqlmesh.core.dialect import parse
|
|
23
24
|
from sqlmesh.core.environment import EnvironmentStatements
|
|
24
25
|
from sqlmesh.core.linter.rule import Rule
|
|
@@ -28,7 +29,6 @@ from sqlmesh.core.metric import Metric, MetricMeta, expand_metrics, load_metric_
|
|
|
28
29
|
from sqlmesh.core.model import (
|
|
29
30
|
Model,
|
|
30
31
|
ModelCache,
|
|
31
|
-
SeedModel,
|
|
32
32
|
create_external_model,
|
|
33
33
|
load_sql_based_models,
|
|
34
34
|
)
|
|
@@ -41,6 +41,7 @@ from sqlmesh.utils.errors import ConfigError
|
|
|
41
41
|
from sqlmesh.utils.jinja import JinjaMacroRegistry, MacroExtractor
|
|
42
42
|
from sqlmesh.utils.metaprogramming import import_python_file
|
|
43
43
|
from sqlmesh.utils.pydantic import validation_error_message
|
|
44
|
+
from sqlmesh.utils.process import create_process_pool_executor
|
|
44
45
|
from sqlmesh.utils.yaml import YAML, load as yaml_load
|
|
45
46
|
|
|
46
47
|
|
|
@@ -48,8 +49,6 @@ if t.TYPE_CHECKING:
|
|
|
48
49
|
from sqlmesh.core.context import GenericContext
|
|
49
50
|
|
|
50
51
|
|
|
51
|
-
logger = logging.getLogger(__name__)
|
|
52
|
-
|
|
53
52
|
GATEWAY_PATTERN = re.compile(r"gateway:\s*([^\s]+)")
|
|
54
53
|
|
|
55
54
|
|
|
@@ -73,17 +72,113 @@ class CacheBase(abc.ABC):
|
|
|
73
72
|
self, target_path: Path, loader: t.Callable[[], t.List[Model]]
|
|
74
73
|
) -> t.List[Model]:
|
|
75
74
|
"""Get or load all models from cache."""
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
@abc.abstractmethod
|
|
78
|
+
def put(self, models: t.List[Model], path: Path) -> bool:
|
|
79
|
+
"""Store models in the cache associated with the given path.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
models: List of models to cache
|
|
83
|
+
path: File path to associate with the cached models
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
True if the models were successfully cached,
|
|
87
|
+
False otherwise (empty list, not a list, unsupported model types)
|
|
88
|
+
"""
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
@abc.abstractmethod
|
|
92
|
+
def get(self, path: Path) -> t.List[Model]:
|
|
93
|
+
"""Retrieve models from the cache for a given path.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
path: File path to look up in the cache
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
List of cached models associated with the path, an empty list if no cache entry exists
|
|
100
|
+
"""
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
_defaults: t.Optional[t.Dict[str, t.Any]] = None
|
|
105
|
+
_cache: t.Optional[CacheBase] = None
|
|
106
|
+
_config_essentials: t.Optional[t.Dict[str, t.Any]] = None
|
|
107
|
+
_selected_gateway: t.Optional[str] = None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _init_model_defaults(
|
|
111
|
+
config_essentials: t.Dict[str, t.Any],
|
|
112
|
+
selected_gateway: t.Optional[str],
|
|
113
|
+
model_loading_defaults: t.Optional[t.Dict[str, t.Any]] = None,
|
|
114
|
+
cache: t.Optional[CacheBase] = None,
|
|
115
|
+
console: t.Optional[Console] = None,
|
|
116
|
+
) -> None:
|
|
117
|
+
global _defaults, _cache, _config_essentials, _selected_gateway
|
|
118
|
+
_defaults = model_loading_defaults
|
|
119
|
+
_cache = cache
|
|
120
|
+
_config_essentials = config_essentials
|
|
121
|
+
_selected_gateway = selected_gateway
|
|
122
|
+
|
|
123
|
+
# Set the console passed from the parent process
|
|
124
|
+
if console is not None:
|
|
125
|
+
from sqlmesh.core.console import set_console
|
|
126
|
+
|
|
127
|
+
set_console(console)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def load_sql_models(path: Path) -> t.List[Model]:
|
|
131
|
+
assert _defaults
|
|
132
|
+
assert _cache
|
|
133
|
+
|
|
134
|
+
with open(path, "r", encoding="utf-8") as file:
|
|
135
|
+
expressions = parse(file.read(), default_dialect=_defaults["dialect"])
|
|
136
|
+
models = load_sql_based_models(expressions, path=Path(path).absolute(), **_defaults)
|
|
137
|
+
|
|
138
|
+
return [] if _cache.put(models, path) else models
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def get_variables(gateway_name: t.Optional[str] = None) -> t.Dict[str, t.Any]:
|
|
142
|
+
assert _config_essentials
|
|
143
|
+
|
|
144
|
+
gateway_name = gateway_name or _selected_gateway
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
gateway = _config_essentials["gateways"].get(gateway_name)
|
|
148
|
+
except ConfigError:
|
|
149
|
+
from sqlmesh.core.console import get_console
|
|
150
|
+
|
|
151
|
+
get_console().log_warning(
|
|
152
|
+
f"Gateway '{gateway_name}' not found in project '{_config_essentials['project']}'."
|
|
153
|
+
)
|
|
154
|
+
gateway = None
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
**_config_essentials["variables"],
|
|
158
|
+
**(gateway.variables if gateway else {}),
|
|
159
|
+
c.GATEWAY: gateway_name,
|
|
160
|
+
}
|
|
76
161
|
|
|
77
162
|
|
|
78
163
|
class Loader(abc.ABC):
|
|
79
164
|
"""Abstract base class to load macros and models for a context"""
|
|
80
165
|
|
|
81
166
|
def __init__(self, context: GenericContext, path: Path) -> None:
|
|
167
|
+
from sqlmesh.core.console import get_console
|
|
168
|
+
|
|
82
169
|
self._path_mtimes: t.Dict[Path, float] = {}
|
|
83
170
|
self.context = context
|
|
84
171
|
self.config_path = path
|
|
85
172
|
self.config = self.context.configs[self.config_path]
|
|
86
173
|
self._variables_by_gateway: t.Dict[str, t.Dict[str, t.Any]] = {}
|
|
174
|
+
self._console = get_console()
|
|
175
|
+
|
|
176
|
+
self.config_essentials = {
|
|
177
|
+
"project": self.config.project,
|
|
178
|
+
"variables": self.config.variables,
|
|
179
|
+
"gateways": self.config.gateways,
|
|
180
|
+
}
|
|
181
|
+
_init_model_defaults(self.config_essentials, self.context.selected_gateway)
|
|
87
182
|
|
|
88
183
|
def load(self) -> LoadedProject:
|
|
89
184
|
"""
|
|
@@ -243,19 +338,21 @@ class Loader(abc.ABC):
|
|
|
243
338
|
for row in YAML().load(file.read())
|
|
244
339
|
]
|
|
245
340
|
except Exception as ex:
|
|
246
|
-
self.
|
|
247
|
-
raise
|
|
341
|
+
raise ConfigError(self._failed_to_load_model_error(path, ex))
|
|
248
342
|
|
|
249
343
|
for path in paths_to_load:
|
|
250
344
|
self._track_file(path)
|
|
251
345
|
|
|
252
346
|
external_models = cache.get_or_load_models(path, lambda: _load(path))
|
|
347
|
+
|
|
253
348
|
# external models with no explicit gateway defined form the base set
|
|
254
349
|
for model in external_models:
|
|
255
350
|
if model.gateway is None:
|
|
256
351
|
if model.fqn in models:
|
|
257
|
-
|
|
258
|
-
|
|
352
|
+
raise ConfigError(
|
|
353
|
+
self._failed_to_load_model_error(
|
|
354
|
+
path, f"Duplicate external model name: '{model.name}'."
|
|
355
|
+
)
|
|
259
356
|
)
|
|
260
357
|
models[model.fqn] = model
|
|
261
358
|
|
|
@@ -264,8 +361,10 @@ class Loader(abc.ABC):
|
|
|
264
361
|
for model in external_models:
|
|
265
362
|
if model.gateway == gateway:
|
|
266
363
|
if model.fqn in models and models[model.fqn].gateway == gateway:
|
|
267
|
-
|
|
268
|
-
|
|
364
|
+
raise ConfigError(
|
|
365
|
+
self._failed_to_load_model_error(
|
|
366
|
+
path, f"Duplicate external model name: '{model.name}'."
|
|
367
|
+
)
|
|
269
368
|
)
|
|
270
369
|
models.update({model.fqn: model})
|
|
271
370
|
|
|
@@ -352,33 +451,11 @@ class Loader(abc.ABC):
|
|
|
352
451
|
"""Project file to track for modifications"""
|
|
353
452
|
self._path_mtimes[path] = path.stat().st_mtime
|
|
354
453
|
|
|
355
|
-
def
|
|
356
|
-
gateway_name = gateway_name or self.context.selected_gateway
|
|
357
|
-
|
|
358
|
-
if gateway_name not in self._variables_by_gateway:
|
|
359
|
-
try:
|
|
360
|
-
gateway = self.config.get_gateway(gateway_name)
|
|
361
|
-
except ConfigError:
|
|
362
|
-
from sqlmesh.core.console import get_console
|
|
363
|
-
|
|
364
|
-
get_console().log_warning(
|
|
365
|
-
f"Gateway '{gateway_name}' not found in project '{self.config.project}'."
|
|
366
|
-
)
|
|
367
|
-
gateway = None
|
|
368
|
-
|
|
369
|
-
self._variables_by_gateway[gateway_name] = {
|
|
370
|
-
**self.config.variables,
|
|
371
|
-
**(gateway.variables if gateway else {}),
|
|
372
|
-
c.GATEWAY: gateway_name,
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return self._variables_by_gateway[gateway_name]
|
|
376
|
-
|
|
377
|
-
def _raise_failed_to_load_model_error(self, path: Path, error: t.Union[str, Exception]) -> None:
|
|
454
|
+
def _failed_to_load_model_error(self, path: Path, error: t.Union[str, Exception]) -> str:
|
|
378
455
|
base_message = f"Failed to load model definition at '{path}':"
|
|
379
456
|
if isinstance(error, ValidationError):
|
|
380
|
-
|
|
381
|
-
|
|
457
|
+
return validation_error_message(error, base_message)
|
|
458
|
+
return f"{base_message}\n {error}"
|
|
382
459
|
|
|
383
460
|
|
|
384
461
|
class SqlMeshLoader(Loader):
|
|
@@ -442,14 +519,15 @@ class SqlMeshLoader(Loader):
|
|
|
442
519
|
audits into a Dict and creates the dag
|
|
443
520
|
"""
|
|
444
521
|
cache = SqlMeshLoader._Cache(self, self.config_path)
|
|
445
|
-
|
|
522
|
+
|
|
523
|
+
sql_models = self._load_sql_models(macros, jinja_macros, audits, signals, cache, gateway)
|
|
446
524
|
external_models = self._load_external_models(audits, cache, gateway)
|
|
447
525
|
python_models = self._load_python_models(macros, jinja_macros, audits, signals)
|
|
448
526
|
|
|
449
527
|
all_model_names = list(sql_models) + list(external_models) + list(python_models)
|
|
450
528
|
duplicates = [name for name, count in Counter(all_model_names).items() if count > 1]
|
|
451
529
|
if duplicates:
|
|
452
|
-
raise
|
|
530
|
+
raise ConfigError(f"Duplicate model name(s) found: {', '.join(duplicates)}.")
|
|
453
531
|
|
|
454
532
|
return UniqueKeyDict("models", **sql_models, **external_models, **python_models)
|
|
455
533
|
|
|
@@ -460,9 +538,12 @@ class SqlMeshLoader(Loader):
|
|
|
460
538
|
audits: UniqueKeyDict[str, ModelAudit],
|
|
461
539
|
signals: UniqueKeyDict[str, signal],
|
|
462
540
|
cache: CacheBase,
|
|
541
|
+
gateway: t.Optional[str],
|
|
463
542
|
) -> UniqueKeyDict[str, Model]:
|
|
464
543
|
"""Loads the sql models into a Dict"""
|
|
465
544
|
models: UniqueKeyDict[str, Model] = UniqueKeyDict("models")
|
|
545
|
+
paths: t.Set[Path] = set()
|
|
546
|
+
cached_paths: UniqueKeyDict[Path, t.List[Model]] = UniqueKeyDict("cached_paths")
|
|
466
547
|
|
|
467
548
|
for path in self._glob_paths(
|
|
468
549
|
self.config_path / c.MODELS,
|
|
@@ -473,48 +554,63 @@ class SqlMeshLoader(Loader):
|
|
|
473
554
|
continue
|
|
474
555
|
|
|
475
556
|
self._track_file(path)
|
|
557
|
+
paths.add(path)
|
|
558
|
+
if cached_models := cache.get(path):
|
|
559
|
+
cached_paths[path] = cached_models
|
|
476
560
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
expressions = parse(
|
|
481
|
-
file.read(), default_dialect=self.config.model_defaults.dialect
|
|
482
|
-
)
|
|
483
|
-
|
|
484
|
-
return load_sql_based_models(
|
|
485
|
-
expressions,
|
|
486
|
-
self._get_variables,
|
|
487
|
-
defaults=self.config.model_defaults.dict(),
|
|
488
|
-
macros=macros,
|
|
489
|
-
jinja_macros=jinja_macros,
|
|
490
|
-
audit_definitions=audits,
|
|
491
|
-
default_audits=self.config.model_defaults.audits,
|
|
492
|
-
path=Path(path).absolute(),
|
|
493
|
-
module_path=self.config_path,
|
|
494
|
-
dialect=self.config.model_defaults.dialect,
|
|
495
|
-
time_column_format=self.config.time_column_format,
|
|
496
|
-
physical_schema_mapping=self.config.physical_schema_mapping,
|
|
497
|
-
project=self.config.project,
|
|
498
|
-
default_catalog=self.context.default_catalog,
|
|
499
|
-
infer_names=self.config.model_naming.infer_names,
|
|
500
|
-
signal_definitions=signals,
|
|
501
|
-
default_catalog_per_gateway=self.context.default_catalog_per_gateway,
|
|
502
|
-
)
|
|
503
|
-
except Exception as ex:
|
|
504
|
-
self._raise_failed_to_load_model_error(path, ex)
|
|
505
|
-
raise
|
|
506
|
-
|
|
507
|
-
for model in cache.get_or_load_models(path, _load):
|
|
508
|
-
if model.fqn in models:
|
|
509
|
-
self._raise_failed_to_load_model_error(
|
|
510
|
-
path, f"Duplicate SQL model name: '{model.name}'."
|
|
511
|
-
)
|
|
561
|
+
for path, cached_models in cached_paths.items():
|
|
562
|
+
paths.remove(path)
|
|
563
|
+
for model in cached_models:
|
|
512
564
|
if model.enabled:
|
|
513
565
|
models[model.fqn] = model
|
|
514
566
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
567
|
+
if paths:
|
|
568
|
+
model_loading_defaults = dict(
|
|
569
|
+
get_variables=get_variables,
|
|
570
|
+
defaults=self.config.model_defaults.dict(),
|
|
571
|
+
macros=macros,
|
|
572
|
+
jinja_macros=jinja_macros,
|
|
573
|
+
audit_definitions=audits,
|
|
574
|
+
default_audits=self.config.model_defaults.audits,
|
|
575
|
+
module_path=self.config_path,
|
|
576
|
+
dialect=self.config.model_defaults.dialect,
|
|
577
|
+
time_column_format=self.config.time_column_format,
|
|
578
|
+
physical_schema_mapping=self.config.physical_schema_mapping,
|
|
579
|
+
project=self.config.project,
|
|
580
|
+
default_catalog=self.context.default_catalog,
|
|
581
|
+
infer_names=self.config.model_naming.infer_names,
|
|
582
|
+
signal_definitions=signals,
|
|
583
|
+
default_catalog_per_gateway=self.context.default_catalog_per_gateway,
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
with create_process_pool_executor(
|
|
587
|
+
initializer=_init_model_defaults,
|
|
588
|
+
initargs=(
|
|
589
|
+
self.config_essentials,
|
|
590
|
+
gateway,
|
|
591
|
+
model_loading_defaults,
|
|
592
|
+
cache,
|
|
593
|
+
self._console,
|
|
594
|
+
),
|
|
595
|
+
max_workers=c.MAX_FORK_WORKERS,
|
|
596
|
+
) as pool:
|
|
597
|
+
futures_to_paths = {pool.submit(load_sql_models, path): path for path in paths}
|
|
598
|
+
for future in concurrent.futures.as_completed(futures_to_paths):
|
|
599
|
+
path = futures_to_paths[future]
|
|
600
|
+
try:
|
|
601
|
+
loaded = future.result()
|
|
602
|
+
for model in loaded or cache.get(path):
|
|
603
|
+
if model.fqn in models:
|
|
604
|
+
raise ConfigError(
|
|
605
|
+
self._failed_to_load_model_error(
|
|
606
|
+
path, f"Duplicate SQL model name: '{model.name}'."
|
|
607
|
+
)
|
|
608
|
+
)
|
|
609
|
+
elif model.enabled:
|
|
610
|
+
model._path = path
|
|
611
|
+
models[model.fqn] = model
|
|
612
|
+
except Exception as ex:
|
|
613
|
+
raise ConfigError(self._failed_to_load_model_error(path, ex))
|
|
518
614
|
|
|
519
615
|
return models
|
|
520
616
|
|
|
@@ -548,7 +644,7 @@ class SqlMeshLoader(Loader):
|
|
|
548
644
|
registered |= new
|
|
549
645
|
for name in new:
|
|
550
646
|
for model in registry[name].models(
|
|
551
|
-
|
|
647
|
+
get_variables,
|
|
552
648
|
path=path,
|
|
553
649
|
module_path=self.config_path,
|
|
554
650
|
defaults=self.config.model_defaults.dict(),
|
|
@@ -566,7 +662,7 @@ class SqlMeshLoader(Loader):
|
|
|
566
662
|
if model.enabled:
|
|
567
663
|
models[model.fqn] = model
|
|
568
664
|
except Exception as ex:
|
|
569
|
-
self.
|
|
665
|
+
raise ConfigError(self._failed_to_load_model_error(path, ex))
|
|
570
666
|
|
|
571
667
|
finally:
|
|
572
668
|
model_registry._dialect = None
|
|
@@ -616,7 +712,7 @@ class SqlMeshLoader(Loader):
|
|
|
616
712
|
"""Loads all the model audits."""
|
|
617
713
|
audits_by_name: UniqueKeyDict[str, Audit] = UniqueKeyDict("audits")
|
|
618
714
|
audits_max_mtime: t.Optional[float] = None
|
|
619
|
-
variables =
|
|
715
|
+
variables = get_variables()
|
|
620
716
|
|
|
621
717
|
for path in self._glob_paths(
|
|
622
718
|
self.config_path / c.AUDITS,
|
|
@@ -692,7 +788,7 @@ class SqlMeshLoader(Loader):
|
|
|
692
788
|
module_path=self.config_path,
|
|
693
789
|
jinja_macro_references=None,
|
|
694
790
|
macros=macros,
|
|
695
|
-
variables=
|
|
791
|
+
variables=get_variables(),
|
|
696
792
|
path=self.config_path,
|
|
697
793
|
)
|
|
698
794
|
|
|
@@ -727,7 +823,7 @@ class SqlMeshLoader(Loader):
|
|
|
727
823
|
gateway_line = GATEWAY_PATTERN.search(source)
|
|
728
824
|
gateway = YAML().load(gateway_line.group(0))["gateway"] if gateway_line else None
|
|
729
825
|
|
|
730
|
-
contents = yaml_load(source, variables=
|
|
826
|
+
contents = yaml_load(source, variables=get_variables(gateway))
|
|
731
827
|
|
|
732
828
|
for test_name, value in contents.items():
|
|
733
829
|
model_test_metadata[test_name] = ModelTestMetadata(
|
|
@@ -785,11 +881,30 @@ class SqlMeshLoader(Loader):
|
|
|
785
881
|
self._model_cache_entry_id(target_path),
|
|
786
882
|
loader=loader,
|
|
787
883
|
)
|
|
884
|
+
|
|
788
885
|
for model in models:
|
|
789
886
|
model._path = target_path
|
|
790
887
|
|
|
791
888
|
return models
|
|
792
889
|
|
|
890
|
+
def put(self, models: t.List[Model], path: Path) -> bool:
|
|
891
|
+
return self._model_cache.put(
|
|
892
|
+
models,
|
|
893
|
+
self._cache_entry_name(path),
|
|
894
|
+
self._model_cache_entry_id(path),
|
|
895
|
+
)
|
|
896
|
+
|
|
897
|
+
def get(self, path: Path) -> t.List[Model]:
|
|
898
|
+
models = self._model_cache.get(
|
|
899
|
+
self._cache_entry_name(path),
|
|
900
|
+
self._model_cache_entry_id(path),
|
|
901
|
+
)
|
|
902
|
+
|
|
903
|
+
for model in models:
|
|
904
|
+
model._path = path
|
|
905
|
+
|
|
906
|
+
return models
|
|
907
|
+
|
|
793
908
|
def _cache_entry_name(self, target_path: Path) -> str:
|
|
794
909
|
return "__".join(target_path.relative_to(self.config_path).parts).replace(
|
|
795
910
|
target_path.suffix, ""
|
sqlmesh/core/model/cache.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
import multiprocessing as mp
|
|
5
4
|
import typing as t
|
|
6
|
-
from concurrent.futures import ProcessPoolExecutor
|
|
7
5
|
from pathlib import Path
|
|
8
6
|
|
|
9
7
|
from sqlglot import exp
|
|
@@ -15,7 +13,7 @@ from sqlmesh.core import constants as c
|
|
|
15
13
|
from sqlmesh.core.model.definition import ExternalModel, Model, SqlModel, _Model
|
|
16
14
|
from sqlmesh.utils.cache import FileCache
|
|
17
15
|
from sqlmesh.utils.hashing import crc32
|
|
18
|
-
from sqlmesh.utils.
|
|
16
|
+
from sqlmesh.utils.process import PoolExecutor, create_process_pool_executor
|
|
19
17
|
|
|
20
18
|
from dataclasses import dataclass
|
|
21
19
|
|
|
@@ -46,12 +44,10 @@ class ModelCache:
|
|
|
46
44
|
self, name: str, entry_id: str = "", *, loader: t.Callable[[], t.List[Model]]
|
|
47
45
|
) -> t.List[Model]:
|
|
48
46
|
"""Returns an existing cached model definition or loads and caches a new one.
|
|
49
|
-
|
|
50
47
|
Args:
|
|
51
48
|
name: The name of the entry.
|
|
52
49
|
entry_id: The unique entry identifier. Used for cache invalidation.
|
|
53
50
|
loader: Used to load a new model definition when no cached instance was found.
|
|
54
|
-
|
|
55
51
|
Returns:
|
|
56
52
|
The model definition.
|
|
57
53
|
"""
|
|
@@ -66,9 +62,22 @@ class ModelCache:
|
|
|
66
62
|
model.full_depends_on
|
|
67
63
|
|
|
68
64
|
self._file_cache.put(name, entry_id, value=models)
|
|
69
|
-
|
|
70
65
|
return models
|
|
71
66
|
|
|
67
|
+
def put(self, models: t.List[Model], name: str, entry_id: str = "") -> bool:
|
|
68
|
+
if models and isinstance(seq_get(models, 0), (SqlModel, ExternalModel)):
|
|
69
|
+
# make sure we preload full_depends_on
|
|
70
|
+
for model in models:
|
|
71
|
+
model.full_depends_on
|
|
72
|
+
|
|
73
|
+
self._file_cache.put(name, entry_id, value=models)
|
|
74
|
+
return True
|
|
75
|
+
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
def get(self, name: str, entry_id: str = "") -> t.List[Model]:
|
|
79
|
+
return self._file_cache.get(name, entry_id) or []
|
|
80
|
+
|
|
72
81
|
|
|
73
82
|
@dataclass
|
|
74
83
|
class OptimizedQueryCacheEntry:
|
|
@@ -149,11 +158,8 @@ class OptimizedQueryCache:
|
|
|
149
158
|
return f"{model.name}_{crc32(hash_data)}"
|
|
150
159
|
|
|
151
160
|
|
|
152
|
-
def optimized_query_cache_pool(optimized_query_cache: OptimizedQueryCache) ->
|
|
153
|
-
|
|
154
|
-
context_type = "spawn" if IS_WINDOWS else "fork"
|
|
155
|
-
return ProcessPoolExecutor(
|
|
156
|
-
mp_context=mp.get_context(context_type),
|
|
161
|
+
def optimized_query_cache_pool(optimized_query_cache: OptimizedQueryCache) -> PoolExecutor:
|
|
162
|
+
return create_process_pool_executor(
|
|
157
163
|
initializer=_init_optimized_query_cache,
|
|
158
164
|
initargs=(optimized_query_cache,),
|
|
159
165
|
max_workers=c.MAX_FORK_WORKERS,
|
sqlmesh/core/model/schema.py
CHANGED
|
@@ -28,10 +28,7 @@ def update_model_schemas(
|
|
|
28
28
|
schema = MappingSchema(normalize=False)
|
|
29
29
|
optimized_query_cache: OptimizedQueryCache = OptimizedQueryCache(context_path / c.CACHE)
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
_update_model_schemas_sequential(dag, models, schema, optimized_query_cache)
|
|
33
|
-
else:
|
|
34
|
-
_update_model_schemas_parallel(dag, models, schema, optimized_query_cache)
|
|
31
|
+
_update_model_schemas(dag, models, schema, optimized_query_cache)
|
|
35
32
|
|
|
36
33
|
|
|
37
34
|
def _update_schema_with_model(schema: MappingSchema, model: Model) -> None:
|
|
@@ -49,25 +46,7 @@ def _update_schema_with_model(schema: MappingSchema, model: Model) -> None:
|
|
|
49
46
|
raise
|
|
50
47
|
|
|
51
48
|
|
|
52
|
-
def
|
|
53
|
-
dag: DAG[str],
|
|
54
|
-
models: UniqueKeyDict[str, Model],
|
|
55
|
-
schema: MappingSchema,
|
|
56
|
-
optimized_query_cache: OptimizedQueryCache,
|
|
57
|
-
) -> None:
|
|
58
|
-
for name in dag.sorted:
|
|
59
|
-
model = models.get(name)
|
|
60
|
-
|
|
61
|
-
# External models don't exist in the context, so we need to skip them
|
|
62
|
-
if not model:
|
|
63
|
-
continue
|
|
64
|
-
|
|
65
|
-
model.update_schema(schema)
|
|
66
|
-
optimized_query_cache.with_optimized_query(model)
|
|
67
|
-
_update_schema_with_model(schema, model)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def _update_model_schemas_parallel(
|
|
49
|
+
def _update_model_schemas(
|
|
71
50
|
dag: DAG[str],
|
|
72
51
|
models: UniqueKeyDict[str, Model],
|
|
73
52
|
schema: MappingSchema,
|
|
@@ -107,12 +86,16 @@ def _update_model_schemas_parallel(
|
|
|
107
86
|
|
|
108
87
|
while futures:
|
|
109
88
|
for future in as_completed(futures):
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
89
|
+
try:
|
|
90
|
+
futures.remove(future)
|
|
91
|
+
fqn, entry_name, data_hash, metadata_hash, mapping_schema = future.result()
|
|
92
|
+
model = models[fqn]
|
|
93
|
+
model._data_hash = data_hash
|
|
94
|
+
model._metadata_hash = metadata_hash
|
|
95
|
+
if model.mapping_schema != mapping_schema:
|
|
96
|
+
model.set_mapping_schema(mapping_schema)
|
|
97
|
+
optimized_query_cache.with_optimized_query(model, entry_name)
|
|
98
|
+
_update_schema_with_model(schema, model)
|
|
99
|
+
process_models(completed_model=model)
|
|
100
|
+
except Exception as ex:
|
|
101
|
+
raise SchemaError(f"Failed to update model schemas\n\n{ex}")
|
sqlmesh/core/snapshot/cache.py
CHANGED
|
@@ -55,20 +55,19 @@ class SnapshotCache:
|
|
|
55
55
|
for snapshot in loaded_snapshots:
|
|
56
56
|
snapshots[snapshot.snapshot_id] = snapshot
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
)
|
|
58
|
+
with optimized_query_cache_pool(self._optimized_query_cache) as executor:
|
|
59
|
+
for key, entry_name in executor.map(
|
|
60
|
+
load_optimized_query,
|
|
61
|
+
(
|
|
62
|
+
(snapshot.model, s_id)
|
|
63
|
+
for s_id, snapshot in snapshots.items()
|
|
64
|
+
if snapshot.is_model
|
|
65
|
+
),
|
|
66
|
+
):
|
|
67
|
+
if entry_name:
|
|
68
|
+
self._optimized_query_cache.with_optimized_query(
|
|
69
|
+
snapshots[key].model, entry_name
|
|
70
|
+
)
|
|
72
71
|
|
|
73
72
|
for snapshot in snapshots.values():
|
|
74
73
|
self._update_node_hash_cache(snapshot)
|
sqlmesh/dbt/loader.py
CHANGED
|
@@ -355,6 +355,19 @@ class DbtLoader(Loader):
|
|
|
355
355
|
|
|
356
356
|
return models
|
|
357
357
|
|
|
358
|
+
def put(self, models: t.List[Model], path: Path) -> bool:
|
|
359
|
+
return self._model_cache.put(
|
|
360
|
+
models,
|
|
361
|
+
self._cache_entry_name(path),
|
|
362
|
+
self._cache_entry_id(path),
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
def get(self, path: Path) -> t.List[Model]:
|
|
366
|
+
return self._model_cache.get(
|
|
367
|
+
self._cache_entry_name(path),
|
|
368
|
+
self._cache_entry_id(path),
|
|
369
|
+
)
|
|
370
|
+
|
|
358
371
|
def _cache_entry_name(self, target_path: Path) -> str:
|
|
359
372
|
try:
|
|
360
373
|
path_for_name = target_path.absolute().relative_to(
|
sqlmesh/utils/concurrency.py
CHANGED
|
@@ -105,16 +105,23 @@ class ConcurrentDAGExecutor(t.Generic[H]):
|
|
|
105
105
|
self._finished_future.set_result(None)
|
|
106
106
|
return
|
|
107
107
|
|
|
108
|
-
skipped_nodes =
|
|
108
|
+
skipped_nodes = {node for node, deps in self._unprocessed_nodes.items() if parent in deps}
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
while skipped_nodes:
|
|
111
|
+
self._skipped_nodes.extend(skipped_nodes)
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
for skipped_node in skipped_nodes:
|
|
114
|
+
self._unprocessed_nodes_num -= 1
|
|
115
|
+
self._unprocessed_nodes.pop(skipped_node)
|
|
116
|
+
|
|
117
|
+
skipped_nodes = {
|
|
118
|
+
node
|
|
119
|
+
for node, deps in self._unprocessed_nodes.items()
|
|
120
|
+
if skipped_nodes.intersection(deps)
|
|
121
|
+
}
|
|
115
122
|
|
|
116
|
-
|
|
117
|
-
self.
|
|
123
|
+
if not self._unprocessed_nodes_num:
|
|
124
|
+
self._finished_future.set_result(None)
|
|
118
125
|
|
|
119
126
|
def _init_state(self) -> None:
|
|
120
127
|
self._unprocessed_nodes = self.dag.graph
|
sqlmesh/utils/process.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# mypy: disable-error-code=no-untyped-def
|
|
2
|
+
|
|
3
|
+
from concurrent.futures import Future, ProcessPoolExecutor
|
|
4
|
+
import typing as t
|
|
5
|
+
import multiprocessing as mp
|
|
6
|
+
from sqlmesh.utils.windows import IS_WINDOWS
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SynchronousPoolExecutor:
|
|
10
|
+
"""A mock implementation of the ProcessPoolExecutor for synchronous use.
|
|
11
|
+
|
|
12
|
+
This executor runs functions synchronously in the same process, avoiding the issues
|
|
13
|
+
with forking in test environments or when forking isn't possible (non-posix).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, max_workers=None, mp_context=None, initializer=None, initargs=()):
|
|
17
|
+
if initializer is not None:
|
|
18
|
+
try:
|
|
19
|
+
initializer(*initargs)
|
|
20
|
+
except BaseException as ex:
|
|
21
|
+
raise RuntimeError(f"Exception in initializer: {ex}")
|
|
22
|
+
|
|
23
|
+
def __enter__(self):
|
|
24
|
+
return self
|
|
25
|
+
|
|
26
|
+
def __exit__(self, *args):
|
|
27
|
+
self.shutdown(wait=True)
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
def shutdown(self, wait=True, cancel_futures=False):
|
|
31
|
+
"""No-op method to match ProcessPoolExecutor API.
|
|
32
|
+
|
|
33
|
+
Since this executor runs synchronously, there are no background processes
|
|
34
|
+
or resources to shut down and all futures will have completed already.
|
|
35
|
+
"""
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
def submit(self, fn, *args, **kwargs):
|
|
39
|
+
"""Execute the function synchronously and return a Future with the result."""
|
|
40
|
+
future = Future()
|
|
41
|
+
try:
|
|
42
|
+
result = fn(*args, **kwargs)
|
|
43
|
+
future.set_result(result)
|
|
44
|
+
except Exception as e:
|
|
45
|
+
future.set_exception(e)
|
|
46
|
+
return future
|
|
47
|
+
|
|
48
|
+
def map(self, fn, *iterables, timeout=None, chunksize=1):
|
|
49
|
+
"""Synchronous implementation of ProcessPoolExecutor.map.
|
|
50
|
+
|
|
51
|
+
This executes the function for each set of inputs from the iterables in the
|
|
52
|
+
current process using Python's built-in map, rather than distributing work.
|
|
53
|
+
"""
|
|
54
|
+
return map(fn, *iterables)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
PoolExecutor = t.Union[SynchronousPoolExecutor, ProcessPoolExecutor]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def create_process_pool_executor(
|
|
61
|
+
initializer: t.Callable, initargs: t.Tuple, max_workers: t.Optional[int]
|
|
62
|
+
) -> PoolExecutor:
|
|
63
|
+
if max_workers == 1 or IS_WINDOWS:
|
|
64
|
+
return SynchronousPoolExecutor(
|
|
65
|
+
initializer=initializer,
|
|
66
|
+
initargs=initargs,
|
|
67
|
+
)
|
|
68
|
+
return ProcessPoolExecutor(
|
|
69
|
+
mp_context=mp.get_context("fork"),
|
|
70
|
+
initializer=initializer,
|
|
71
|
+
initargs=initargs,
|
|
72
|
+
max_workers=max_workers,
|
|
73
|
+
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
sqlmesh/__init__.py,sha256=69xw6bTmi4cW90M-sl3g6wLDgxVcLHcKg1q8GS3lqyA,7466
|
|
2
|
-
sqlmesh/_version.py,sha256=
|
|
2
|
+
sqlmesh/_version.py,sha256=vqg9_bdM0w1PriGacvlThb4jS8xV-36vEdbL-x7PuiI,530
|
|
3
3
|
sqlmesh/magics.py,sha256=JHorAZNtezf123jmTyNSoUC9yHmv-08hMP205PJmmIo,39750
|
|
4
4
|
sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -18,7 +18,7 @@ sqlmesh/core/context_diff.py,sha256=s9toP17d4tJfOpFH91LcjGK2CM64PVuB0MPkeFgF4hQ,
|
|
|
18
18
|
sqlmesh/core/dialect.py,sha256=fPTV517IOS0nWMxYznNNQnXkQkFFrPOSKe8ghsQ0o8A,49759
|
|
19
19
|
sqlmesh/core/environment.py,sha256=0TTQf4C4LXwf37fm-dfYv1qyG7vtZfQI5rizgm5g0j0,11442
|
|
20
20
|
sqlmesh/core/lineage.py,sha256=zjB0Zfamo2Fja2r5SSZPMbrEKTXr1WjozZPVqvxdybI,3143
|
|
21
|
-
sqlmesh/core/loader.py,sha256=
|
|
21
|
+
sqlmesh/core/loader.py,sha256=exNCHmw06-CRBtOk-Hk5Ivw3gCowDWbxcvhMJVxpDd8,35887
|
|
22
22
|
sqlmesh/core/macros.py,sha256=wSKkFDZ2eIvhPENIsQ_7j27zVMHIgT-2juRjGvDeEKM,59620
|
|
23
23
|
sqlmesh/core/node.py,sha256=r4_1MRTPcU0MAlwZ5KzrykLT58B7dkKvHzPCsJmEKD8,14497
|
|
24
24
|
sqlmesh/core/notification_target.py,sha256=PPGoDrgbRKxr27vJEu03XqNTQLYTw0ZF_b0yAapxGeI,16158
|
|
@@ -84,20 +84,20 @@ sqlmesh/core/metric/__init__.py,sha256=H1HmoD5IwN4YWe9iJXyueLYNmTQFZwok5nSWNJcZI
|
|
|
84
84
|
sqlmesh/core/metric/definition.py,sha256=Yd5aVgsZCDPJ43aGP7WqtzZOuuSUtB8uJGVA6Jw9x9M,7201
|
|
85
85
|
sqlmesh/core/metric/rewriter.py,sha256=GiSTHfn2kinqCfNPYgZPRk93JFLzVaaejHtHDQ0yXZI,7326
|
|
86
86
|
sqlmesh/core/model/__init__.py,sha256=C8GRZ53xuXEA9hQv3BQS9pNNyd9rZ06R_B96UYGhDu4,1644
|
|
87
|
-
sqlmesh/core/model/cache.py,sha256=
|
|
87
|
+
sqlmesh/core/model/cache.py,sha256=WJdn54xmA3NtX0dlX-DZnYlrWDhj4ycoq_4FD4MK2yg,7502
|
|
88
88
|
sqlmesh/core/model/common.py,sha256=vbcXFhWE22-FeKYAVIlKWvTb-wkeC8XISjU_TIlak0c,16252
|
|
89
89
|
sqlmesh/core/model/decorator.py,sha256=v_sVudNROGrtj5cZ3vgcOFnwPdzwoUGY6REAkQpIMQc,8927
|
|
90
90
|
sqlmesh/core/model/definition.py,sha256=QBwGNL7Jqg8BGgpZfTtKciRJA7axkI5FShJJjnUDQ4w,108645
|
|
91
91
|
sqlmesh/core/model/kind.py,sha256=i6_AMBarXPGPoMdF9kzBkyqS9tu__a2339-BoX7TgCM,36010
|
|
92
92
|
sqlmesh/core/model/meta.py,sha256=osJgfSj6maIIdWAHzDVCkXXL--__gnKvqkzxM6Nuq6g,20779
|
|
93
|
-
sqlmesh/core/model/schema.py,sha256=
|
|
93
|
+
sqlmesh/core/model/schema.py,sha256=OClbAeA8LpW-IiSiLT_TlDWkEqmIIvSk0GXq8SWI-GQ,3443
|
|
94
94
|
sqlmesh/core/model/seed.py,sha256=ctUHH6CmeEnBVJyIAZznx0xJBm09W7VIZ-76Cfwfq28,5004
|
|
95
95
|
sqlmesh/core/plan/__init__.py,sha256=ctpnu9mK3uTujs0It8qRMqcj9GdObXDnvSgn4rD2zqc,450
|
|
96
96
|
sqlmesh/core/plan/builder.py,sha256=Fd5raxq6r6b_3mOZndiI2U7SmliVYevcrpxWNqRV_OE,38471
|
|
97
97
|
sqlmesh/core/plan/definition.py,sha256=SI3zi2poPkKJKTZogYv60Q7eIOhksaAcFUcu-J2-XqI,13218
|
|
98
98
|
sqlmesh/core/plan/evaluator.py,sha256=RAHJgQoV5Y5SIG_pV2O_Bn0VFlD1yzMC0UrUU6eaB_E,26842
|
|
99
99
|
sqlmesh/core/snapshot/__init__.py,sha256=Z5HTetNCZGoKF1WAKXk4LWL9dc8EC8lwS2O4TtoBmt4,1317
|
|
100
|
-
sqlmesh/core/snapshot/cache.py,sha256=
|
|
100
|
+
sqlmesh/core/snapshot/cache.py,sha256=bgqCR2hyf6r2A_8QP1EnXFK25gDX37-Zg0YeMuETWxg,3934
|
|
101
101
|
sqlmesh/core/snapshot/categorizer.py,sha256=qGG5870mu1jR2whKisSBH_GFbsyh96RnzJDgkN7DV9g,2482
|
|
102
102
|
sqlmesh/core/snapshot/definition.py,sha256=PKzBLiQ1yIycGbmslEoQyJEwtfnJHsQuY_sl1xkBcvk,84081
|
|
103
103
|
sqlmesh/core/snapshot/evaluator.py,sha256=Y01dkakdX-Jvz3t8DAzJPLVt3eL2DRqz7SabgZ7ME7g,89430
|
|
@@ -127,7 +127,7 @@ sqlmesh/dbt/builtin.py,sha256=fyzv4qR1isfnID1oWz-r46oDQvS90DN5mMUEWgapvN8,15153
|
|
|
127
127
|
sqlmesh/dbt/column.py,sha256=Kvj_N3D_QegcoNQG7VqRiqy-FRfupud-6ilhlykBOgE,1873
|
|
128
128
|
sqlmesh/dbt/common.py,sha256=g4PAL-sEdlnfb_zT-WW3xh-oamyCUoK8dUiDEMVwDWI,7804
|
|
129
129
|
sqlmesh/dbt/context.py,sha256=dxClM-G1IeMbP0v5yxC_va8QNU-uKghW2dBlSZHJOk0,10331
|
|
130
|
-
sqlmesh/dbt/loader.py,sha256=
|
|
130
|
+
sqlmesh/dbt/loader.py,sha256=dXnqs_MmbP5u1CzoCviQpA_i0XCaEvm_L3kJTWOmFJ8,16024
|
|
131
131
|
sqlmesh/dbt/manifest.py,sha256=iKfUWiqydIW3YnX6hqWAzRc-TmhiXfVFS7e29XJaS6E,22906
|
|
132
132
|
sqlmesh/dbt/model.py,sha256=-TqeldZAqW-4g84Xi_16DpUD3atImk_9OHMbATIKYb8,26328
|
|
133
133
|
sqlmesh/dbt/package.py,sha256=WM5Ve6o0QPW3rZxhw1xbr3yX2619I5KtHOKK1qe5mfU,4291
|
|
@@ -251,7 +251,7 @@ sqlmesh/schedulers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
|
251
251
|
sqlmesh/utils/__init__.py,sha256=4vN2s-t0p0c9l4erdOFONl_j8StaW6Eljt_SBffMW80,10898
|
|
252
252
|
sqlmesh/utils/aws.py,sha256=krxyhrKtsMJDEjT567UbGZogjJ9JRHkvAV-Cg3FVndM,1062
|
|
253
253
|
sqlmesh/utils/cache.py,sha256=GITQ3sldwG4vlI0wKIDI7yOr1CND1EI3necAmeCEW8g,4743
|
|
254
|
-
sqlmesh/utils/concurrency.py,sha256=
|
|
254
|
+
sqlmesh/utils/concurrency.py,sha256=EMgEecfPFN9_2Wjz4TUksJngECGse7fnKVcLswkmhAk,9274
|
|
255
255
|
sqlmesh/utils/config.py,sha256=-SjIn7Z0HHnMtjPavQIvFcSaeg86XLsGd3sGIwOKrTE,1941
|
|
256
256
|
sqlmesh/utils/connection_pool.py,sha256=To1zr9d5MQOZ5im09jLQKO4DFmfzH6s_q75cEa1y0PE,11390
|
|
257
257
|
sqlmesh/utils/conversions.py,sha256=Ul8u6TzlKzFz_lVrUzFSzmJBKHUXOYe2e-xmkMXV084,406
|
|
@@ -265,11 +265,12 @@ sqlmesh/utils/jinja.py,sha256=6Iob2Pv88L2rCaHyl_V90b5GKsG9hI10Ua_FRWhQIl0,23628
|
|
|
265
265
|
sqlmesh/utils/metaprogramming.py,sha256=i1rxWi-oxdh1VwKoBh5Qvy0GgHm9GaDZMvIrv3QXGt4,23083
|
|
266
266
|
sqlmesh/utils/migration.py,sha256=R7Ck6FX-LfcujGy7sgS0kDWlK-xAEBODr3gqIQ8gC08,835
|
|
267
267
|
sqlmesh/utils/pandas.py,sha256=uKI-ygEtMcGDRzXdBu0RkGmMBkYxwu5O2Wabho841Ls,2196
|
|
268
|
+
sqlmesh/utils/process.py,sha256=vpXcpJ1eIbivs7gZdwTKSJI7OS6kKBebnaBzz75ykvs,2428
|
|
268
269
|
sqlmesh/utils/pydantic.py,sha256=I898jAFqa3qU6lG2uPpRebVFncOUo8ZrLWM_R3K3DHU,11685
|
|
269
270
|
sqlmesh/utils/rich.py,sha256=xNZyPCqEc4TAlJlsEthg-5eYUWpaizz0QjBzO7a1Yv4,1509
|
|
270
271
|
sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
|
|
271
272
|
sqlmesh/utils/yaml.py,sha256=np-WVcwmwsKghCgAj1OBBMsK1SXSRn4wR-H37cGiFr8,2282
|
|
272
|
-
sqlmesh-0.186.2.
|
|
273
|
+
sqlmesh-0.186.2.dev13.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
|
|
273
274
|
web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
274
275
|
web/client/dist/index.html,sha256=M50OuwjW63dRCS0Dz40Yecgvw9ecLFqizbTa6gv5Nd4,5472
|
|
275
276
|
web/client/dist/assets/Audits-BPlxzqeG.js,sha256=TCx1qCjCGgmUSvH6HoPr5t8ztbRXMlOxrcW4o7hRjlA,1041
|
|
@@ -387,8 +388,8 @@ web/server/api/endpoints/models.py,sha256=ud-lRwriyI_OYg9tZchrBgeiXELiRTLNEodraf
|
|
|
387
388
|
web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
|
|
388
389
|
web/server/api/endpoints/plan.py,sha256=OYuQ_4dgbhG9ibTcX1a8mvYgH3ANxw9Fhbb4wg6QWqc,9222
|
|
389
390
|
web/server/api/endpoints/table_diff.py,sha256=Wd5YxeKbZB7AkrDvqFgvV9ZQlnKYOF1n5W_w2EHE_Zw,2085
|
|
390
|
-
sqlmesh-0.186.2.
|
|
391
|
-
sqlmesh-0.186.2.
|
|
392
|
-
sqlmesh-0.186.2.
|
|
393
|
-
sqlmesh-0.186.2.
|
|
394
|
-
sqlmesh-0.186.2.
|
|
391
|
+
sqlmesh-0.186.2.dev13.dist-info/METADATA,sha256=QBfR5Kg6iu6zN8kIiC1cIN6mgeWn77raK94c3frUaq8,25524
|
|
392
|
+
sqlmesh-0.186.2.dev13.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
393
|
+
sqlmesh-0.186.2.dev13.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
|
|
394
|
+
sqlmesh-0.186.2.dev13.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
|
|
395
|
+
sqlmesh-0.186.2.dev13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|