sqlmesh 0.184.3.dev10__py3-none-any.whl → 0.184.3.dev12__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 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.184.3.dev10'
21
- __version_tuple__ = version_tuple = (0, 184, 3, 'dev10')
20
+ __version__ = version = '0.184.3.dev12'
21
+ __version_tuple__ = version_tuple = (0, 184, 3, 'dev12')
@@ -8,7 +8,7 @@ from sqlmesh.utils.aws import validate_s3_uri, parse_s3_uri
8
8
  from sqlmesh.core.engine_adapter.mixins import PandasNativeFetchDFSupportMixin, RowDiffMixin
9
9
  from sqlmesh.core.engine_adapter.trino import TrinoEngineAdapter
10
10
  from sqlmesh.core.node import IntervalUnit
11
- import os
11
+ import posixpath
12
12
  from sqlmesh.utils.errors import SQLMeshError
13
13
  from sqlmesh.core.engine_adapter.shared import (
14
14
  CatalogSupport,
@@ -403,11 +403,13 @@ class AthenaEngineAdapter(PandasNativeFetchDFSupportMixin, RowDiffMixin):
403
403
 
404
404
  elif self.s3_warehouse_location:
405
405
  # If the user has set `s3_warehouse_location` in the connection config, the base URI is <s3_warehouse_location>/<catalog>/<schema>/
406
- base_uri = os.path.join(self.s3_warehouse_location, table.catalog or "", table.db or "")
406
+ base_uri = posixpath.join(
407
+ self.s3_warehouse_location, table.catalog or "", table.db or ""
408
+ )
407
409
  else:
408
410
  return None
409
411
 
410
- full_uri = validate_s3_uri(os.path.join(base_uri, table.text("this") or ""), base=True)
412
+ full_uri = validate_s3_uri(posixpath.join(base_uri, table.text("this") or ""), base=True)
411
413
  return exp.LocationProperty(this=exp.Literal.string(full_uri))
412
414
 
413
415
  def _find_matching_columns(
@@ -15,6 +15,7 @@ from sqlmesh.core import constants as c
15
15
  from sqlmesh.core.model.definition import ExternalModel, Model, SqlModel, _Model
16
16
  from sqlmesh.utils.cache import FileCache
17
17
  from sqlmesh.utils.hashing import crc32
18
+ from sqlmesh.utils.windows import IS_WINDOWS
18
19
 
19
20
  from dataclasses import dataclass
20
21
 
@@ -149,8 +150,10 @@ class OptimizedQueryCache:
149
150
 
150
151
 
151
152
  def optimized_query_cache_pool(optimized_query_cache: OptimizedQueryCache) -> ProcessPoolExecutor:
153
+ # fork doesnt work on Windows. ref: https://docs.python.org/3/library/multiprocessing.html#multiprocessing-start-methods
154
+ context_type = "spawn" if IS_WINDOWS else "fork"
152
155
  return ProcessPoolExecutor(
153
- mp_context=mp.get_context("fork"),
156
+ mp_context=mp.get_context(context_type),
154
157
  initializer=_init_optimized_query_cache,
155
158
  initargs=(optimized_query_cache,),
156
159
  max_workers=c.MAX_FORK_WORKERS,
sqlmesh/utils/cache.py CHANGED
@@ -12,6 +12,7 @@ from sqlglot import __version__ as SQLGLOT_VERSION
12
12
  from sqlmesh.utils import sanitize_name
13
13
  from sqlmesh.utils.date import to_datetime
14
14
  from sqlmesh.utils.errors import SQLMeshError
15
+ from sqlmesh.utils.windows import IS_WINDOWS, fix_windows_path
15
16
 
16
17
  logger = logging.getLogger(__name__)
17
18
 
@@ -132,4 +133,8 @@ class FileCache(t.Generic[T]):
132
133
 
133
134
  def _cache_entry_path(self, name: str, entry_id: str = "") -> Path:
134
135
  entry_file_name = "__".join(p for p in (self._cache_version, name, entry_id) if p)
135
- return self._path / sanitize_name(entry_file_name)
136
+ full_path = self._path / sanitize_name(entry_file_name)
137
+ if IS_WINDOWS:
138
+ # handle paths longer than 260 chars
139
+ full_path = fix_windows_path(full_path)
140
+ return full_path
@@ -0,0 +1,14 @@
1
+ import platform
2
+ from pathlib import Path
3
+
4
+ IS_WINDOWS = platform.system() == "Windows"
5
+
6
+
7
+ def fix_windows_path(path: Path) -> Path:
8
+ """
9
+ Windows paths are limited to 260 characters: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
10
+ Users can change this by updating a registry entry but we cant rely on that.
11
+ We can quite commonly generate a cache file path that exceeds 260 characters which causes a FileNotFound error.
12
+ If we prefix the path with "\\?\" then we can have paths up to 32,767 characters
13
+ """
14
+ return Path("\\\\?\\" + str(path.absolute()))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmesh
3
- Version: 0.184.3.dev10
3
+ Version: 0.184.3.dev12
4
4
  Summary: Next-generation data transformation framework
5
5
  Author-email: "TobikoData Inc." <engineering@tobikodata.com>
6
6
  License: Apache License
@@ -1,5 +1,5 @@
1
1
  sqlmesh/__init__.py,sha256=DRovDXI-9D9xeYDP7t8Fq7mI31S2btlN-LHPOK3y7PA,7240
2
- sqlmesh/_version.py,sha256=jFzBB3tos-4Z7mIfsDO0P_7HdqxK3J2sRk8mGivtBkI,530
2
+ sqlmesh/_version.py,sha256=zRNKjsN4O0fNwBz4jqBqT0B-wSHyRN-M0SWZHxxCSZ8,530
3
3
  sqlmesh/magics.py,sha256=aeOyTdeNnyGzGtJXECDAbqJ8OAplrV4UAYl0I2hhtig,39670
4
4
  sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -58,7 +58,7 @@ sqlmesh/core/config/scheduler.py,sha256=essKKkJ6jD5gRT_l-WiKwGKVO1hpDlnf_UdrCvyN
58
58
  sqlmesh/core/config/ui.py,sha256=jsO-S6_d9NkLZGG5pT4mgKgxMF34KzkDociZAMvCX3U,278
59
59
  sqlmesh/core/engine_adapter/__init__.py,sha256=two_WTs4UnSNp-fscJh8vOunJq0Xi37EuDuMjKsKuNE,2281
60
60
  sqlmesh/core/engine_adapter/_typing.py,sha256=BAM_U7Vsi0k37XHu_nNnu3whXxuTVDey_uZe3aelKYY,1033
61
- sqlmesh/core/engine_adapter/athena.py,sha256=kVkGhDhjVd_8zsvq7B94kr_CHD0bct6XXFkhzrOjQOY,26158
61
+ sqlmesh/core/engine_adapter/athena.py,sha256=WBVAB_YzBJXdiqq51LTd2jmYoMtGrLmtsA8IrIFVnQ0,26199
62
62
  sqlmesh/core/engine_adapter/base.py,sha256=XQeJi4Rr5VllnQKFZBYXNs1G142T16ZOVU_l9UYvzoE,100539
63
63
  sqlmesh/core/engine_adapter/base_postgres.py,sha256=DOsOdCJyQAVfA9S0GznuH0J1bonMqYVP_yJLDYcxFYM,6772
64
64
  sqlmesh/core/engine_adapter/bigquery.py,sha256=gnd2cFc7v95tT_E9XMHHgccS-QwSF2sJHsL8xfcSguk,49249
@@ -84,7 +84,7 @@ 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=hzpGPXxp2LFMEp6gm-8DULJKCBDGf-1kTQcfNt0xrRM,7028
87
+ sqlmesh/core/model/cache.py,sha256=s-aEFuUmUKITaWHvYbOyRarsjsgoA6vfASK-f-MwJ9k,7257
88
88
  sqlmesh/core/model/common.py,sha256=J3ukpCEvZyfiYlG38aMhqxlR-Tyq2Sm2dzg5SOnldXc,16279
89
89
  sqlmesh/core/model/decorator.py,sha256=v_sVudNROGrtj5cZ3vgcOFnwPdzwoUGY6REAkQpIMQc,8927
90
90
  sqlmesh/core/model/definition.py,sha256=vR9Y48WTZTHbjlvuQltueXNxBtVoWpxCw4D9cikRqw4,108422
@@ -249,7 +249,7 @@ sqlmesh/migrations/v0083_use_sql_for_scd_time_data_type_data_hash.py,sha256=0r-S
249
249
  sqlmesh/schedulers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
250
250
  sqlmesh/utils/__init__.py,sha256=4vN2s-t0p0c9l4erdOFONl_j8StaW6Eljt_SBffMW80,10898
251
251
  sqlmesh/utils/aws.py,sha256=krxyhrKtsMJDEjT567UbGZogjJ9JRHkvAV-Cg3FVndM,1062
252
- sqlmesh/utils/cache.py,sha256=y58l95ka8RgSX-r6Opav4RBKWLnNYLUYqLfDOPI8HzI,4526
252
+ sqlmesh/utils/cache.py,sha256=GITQ3sldwG4vlI0wKIDI7yOr1CND1EI3necAmeCEW8g,4743
253
253
  sqlmesh/utils/concurrency.py,sha256=HvK_AwVfy3Npzmsthmd73Z5tLhY-Anrb472IkaoRjOw,9041
254
254
  sqlmesh/utils/config.py,sha256=-SjIn7Z0HHnMtjPavQIvFcSaeg86XLsGd3sGIwOKrTE,1941
255
255
  sqlmesh/utils/connection_pool.py,sha256=To1zr9d5MQOZ5im09jLQKO4DFmfzH6s_q75cEa1y0PE,11390
@@ -266,8 +266,9 @@ sqlmesh/utils/migration.py,sha256=R7Ck6FX-LfcujGy7sgS0kDWlK-xAEBODr3gqIQ8gC08,83
266
266
  sqlmesh/utils/pandas.py,sha256=uKI-ygEtMcGDRzXdBu0RkGmMBkYxwu5O2Wabho841Ls,2196
267
267
  sqlmesh/utils/pydantic.py,sha256=-u69PDY-4FLR7ODNKBoN7PsPNmZ0wdhsJcCAG2P6vyY,11061
268
268
  sqlmesh/utils/rich.py,sha256=xNZyPCqEc4TAlJlsEthg-5eYUWpaizz0QjBzO7a1Yv4,1509
269
+ sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
269
270
  sqlmesh/utils/yaml.py,sha256=np-WVcwmwsKghCgAj1OBBMsK1SXSRn4wR-H37cGiFr8,2282
270
- sqlmesh-0.184.3.dev10.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
271
+ sqlmesh-0.184.3.dev12.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
271
272
  web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
272
273
  web/client/dist/index.html,sha256=h-jIuvBTQ-QurWEds39umXiJjP_TWPQmkHTiizCAeOI,5472
273
274
  web/client/dist/assets/Audits-DIPZFtrx.js,sha256=Yn24xPBT3znH0fQJJaBLb1p1wjJz1nWjrZcm18e63W0,1041
@@ -367,26 +368,26 @@ web/server/app.py,sha256=b6qEJ4btjaSm2kWwQUGV--S3VE8QW0Um7f4rBdaoB_M,59
367
368
  web/server/console.py,sha256=K2fJpiZbibWaQa2OvN7YbeI9sxkXtkXwA8lJKsXfq-k,14529
368
369
  web/server/exceptions.py,sha256=I2PPpChwhDWawQENr5kHg6DjyRGeiJ6OWZsCzEZhVzs,1533
369
370
  web/server/main.py,sha256=9PaDa8sigo1z0AxtI3sQ3fHmDqs6uXwP-_IvoMwkznw,3199
370
- web/server/models.py,sha256=SUztvOYmlHDMVOt7C36-C3tKBwm7UNRkkYeid9bc5n8,15527
371
+ web/server/models.py,sha256=NUI2xqDcav20uuC2BZ9xDL2x0v16-gpVT1Sb-WHfAcg,15518
371
372
  web/server/openapi.py,sha256=NOg__YQg7arVdajQv5CvOA5KLTQCfGZFvwnjARuM6iE,586
372
373
  web/server/settings.py,sha256=PuWrOmn5LpJMBTymCMQreqMsL93tClTJ6wlcAZXjgCo,3755
373
- web/server/utils.py,sha256=h_CpJe_2PvWhAZ_S2q8SWRf5olvdjAj3lnhusiVXexY,3286
374
+ web/server/utils.py,sha256=WodQI75kQTXVCO_g1g9Sf0_b-9yoYFieb_xcKRpZ470,3986
374
375
  web/server/watcher.py,sha256=5biJ8gbHmGNUrooMFWRmw00XDVg0bMx6Hub571cs6TI,5246
375
376
  web/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
376
377
  web/server/api/endpoints/__init__.py,sha256=FcXl56-kPqbKgCZKOx0kjE50hn37q1m-nwOCxI9tRcc,932
377
- web/server/api/endpoints/commands.py,sha256=GuYgrstMxpKYAHaH7EGYTLZdY8J21nlNQX2f-EK66ZY,8243
378
+ web/server/api/endpoints/commands.py,sha256=MVlxC-QG6VMEcboHYeuTdtsd7WgPpqJcQDa1OLxZtLI,8367
378
379
  web/server/api/endpoints/directories.py,sha256=Aa8U4pTs3Saj5DnJ9TDnX9mZois-EXgpcBm5GpNNM_s,1822
379
380
  web/server/api/endpoints/environments.py,sha256=g3YC6j4LLlG_wjJqn-Hrz78BWmgS7vhUhzaycsiez00,2124
380
381
  web/server/api/endpoints/events.py,sha256=tjhOhGe9jt7L1mOLLapl5qTvicDRnP5lPZHSq9OnSVI,932
381
- web/server/api/endpoints/files.py,sha256=UnZPScF-HANNNZhNFhxfAPihcU3p85mB7P2rqFc2wG4,6698
382
+ web/server/api/endpoints/files.py,sha256=HogdDH35tHBPLu_4vwj2aXrAqikA2UdkCOLv5QXf0Ng,6720
382
383
  web/server/api/endpoints/lineage.py,sha256=re2mNADlUQsBZVeA7jKw857mQvMxwijynP5iVB7YAnY,5769
383
384
  web/server/api/endpoints/meta.py,sha256=QKWWrHewGh5JS8mCSWXTKCIQwXw-TQfaT9tWt_SsNY4,1032
384
- web/server/api/endpoints/models.py,sha256=SzS5bshzdXyM6hb948sZ_3k-xhpGCHkxkb7pHzPjM_o,4675
385
+ web/server/api/endpoints/models.py,sha256=ud-lRwriyI_OYg9tZchrBgeiXELiRTLNEodrafB7Ndk,4697
385
386
  web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
386
387
  web/server/api/endpoints/plan.py,sha256=OYuQ_4dgbhG9ibTcX1a8mvYgH3ANxw9Fhbb4wg6QWqc,9222
387
388
  web/server/api/endpoints/table_diff.py,sha256=Wd5YxeKbZB7AkrDvqFgvV9ZQlnKYOF1n5W_w2EHE_Zw,2085
388
- sqlmesh-0.184.3.dev10.dist-info/METADATA,sha256=Vsg4xUkm0XISAr4Mr31UoAvyqBR3PxXLiyT9p-TNg-I,25499
389
- sqlmesh-0.184.3.dev10.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
390
- sqlmesh-0.184.3.dev10.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
391
- sqlmesh-0.184.3.dev10.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
392
- sqlmesh-0.184.3.dev10.dist-info/RECORD,,
389
+ sqlmesh-0.184.3.dev12.dist-info/METADATA,sha256=0DY4ysd-BS4Bqm9s3CORlButuv1lwL7tY2wSFzagOf8,25499
390
+ sqlmesh-0.184.3.dev12.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
391
+ sqlmesh-0.184.3.dev12.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
392
+ sqlmesh-0.184.3.dev12.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
393
+ sqlmesh-0.184.3.dev12.dist-info/RECORD,,
@@ -22,6 +22,7 @@ from web.server.utils import (
22
22
  df_to_pyarrow_bytes,
23
23
  run_in_executor,
24
24
  )
25
+ from pathlib import Path
25
26
 
26
27
  router = APIRouter()
27
28
 
@@ -143,7 +144,7 @@ async def test(
143
144
  test_output = io.StringIO()
144
145
  try:
145
146
  result = context.test(
146
- tests=[str(context.path / test)] if test else None,
147
+ tests=[str(context.path / Path(test))] if test else None,
147
148
  verbosity=verbosity,
148
149
  stream=test_output,
149
150
  )
@@ -160,11 +161,17 @@ async def test(
160
161
  test_output.getvalue(),
161
162
  context._test_connection_config._engine_adapter.DIALECT,
162
163
  )
164
+
165
+ def _test_path(test: ModelTest) -> t.Optional[str]:
166
+ if path := test.path_relative_to(context.path):
167
+ return path.as_posix()
168
+ return None
169
+
163
170
  return models.TestResult(
164
171
  errors=[
165
172
  models.TestErrorOrFailure(
166
173
  name=test.test_name,
167
- path=test.path_relative_to(context.path),
174
+ path=_test_path(test),
168
175
  tb=tb,
169
176
  )
170
177
  for test, tb in ((t.cast(ModelTest, test), tb) for test, tb in result.errors)
@@ -172,7 +179,7 @@ async def test(
172
179
  failures=[
173
180
  models.TestErrorOrFailure(
174
181
  name=test.test_name,
175
- path=test.path_relative_to(context.path),
182
+ path=_test_path(test),
176
183
  tb=tb,
177
184
  )
178
185
  for test, tb in ((t.cast(ModelTest, test), tb) for test, tb in result.failures)
@@ -180,7 +187,7 @@ async def test(
180
187
  skipped=[
181
188
  models.TestSkipped(
182
189
  name=test.test_name,
183
- path=test.path_relative_to(context.path),
190
+ path=_test_path(test),
184
191
  reason=reason,
185
192
  )
186
193
  for test, reason in (
@@ -190,7 +197,7 @@ async def test(
190
197
  successes=[
191
198
  models.TestCase(
192
199
  name=test.test_name,
193
- path=test.path_relative_to(context.path),
200
+ path=_test_path(test),
194
201
  )
195
202
  for test in (t.cast(ModelTest, test) for test in result.successes)
196
203
  ],
@@ -145,13 +145,13 @@ def _get_directory(path: str | Path, settings: Settings) -> models.Directory:
145
145
  directories.append(
146
146
  models.Directory(
147
147
  name=entry.name,
148
- path=str(relative_path),
148
+ path=str(relative_path.as_posix()),
149
149
  directories=_directories,
150
150
  files=_files,
151
151
  )
152
152
  )
153
153
  elif entry.is_file(follow_symlinks=False):
154
- files.append(models.File(name=entry.name, path=str(relative_path)))
154
+ files.append(models.File(name=entry.name, path=str(relative_path.as_posix())))
155
155
  return sorted(directories, key=lambda x: x.name), sorted(files, key=lambda x: x.name)
156
156
 
157
157
  directories, files = walk_path(path)
@@ -124,8 +124,8 @@ def serialize_model(context: Context, model: Model, render_query: bool = False)
124
124
  return models.Model(
125
125
  name=model.name,
126
126
  fqn=model.fqn,
127
- path=str(model._path.absolute().relative_to(context.path)),
128
- full_path=str(model._path.absolute()),
127
+ path=str(model._path.absolute().relative_to(context.path).as_posix()),
128
+ full_path=str(model._path.absolute().as_posix()),
129
129
  dialect=dialect,
130
130
  columns=columns,
131
131
  details=details,
web/server/models.py CHANGED
@@ -420,7 +420,7 @@ class TableDiff(PydanticModel):
420
420
 
421
421
  class TestCase(PydanticModel):
422
422
  name: str
423
- path: pathlib.Path
423
+ path: str
424
424
 
425
425
 
426
426
  class TestErrorOrFailure(TestCase):
web/server/utils.py CHANGED
@@ -16,6 +16,7 @@ from sqlmesh.core import constants as c
16
16
  from web.server.console import api_console
17
17
  from web.server.exceptions import ApiException
18
18
  from web.server.settings import Settings, get_context, get_settings
19
+ from sqlmesh.utils.windows import IS_WINDOWS
19
20
 
20
21
  R = t.TypeVar("R")
21
22
 
@@ -75,6 +76,16 @@ def replace_file(src: Path, dst: Path) -> None:
75
76
  """Move a file or directory at src to dst."""
76
77
  if src != dst:
77
78
  try:
79
+ if IS_WINDOWS:
80
+ # os.replace() behaves differently on Windows so we have to do some extra checks
81
+ if dst.exists():
82
+ if src.exists() and src.is_dir() and dst.is_file():
83
+ raise OSError("Cant rename directory to existing file")
84
+ elif src.exists() and src.is_file() and dst.is_dir():
85
+ raise OSError("Cant rename file to existing directory")
86
+ elif dst.is_dir() and not any(dst.iterdir()):
87
+ # target dir exists but is empty, delete it so replace() succeeds
88
+ dst.rmdir()
78
89
  src.replace(dst)
79
90
  except FileNotFoundError:
80
91
  raise HTTPException(status_code=HTTP_404_NOT_FOUND)