sqlmesh 0.184.3.dev11__py3-none-any.whl → 0.184.3.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/engine_adapter/athena.py +5 -3
- sqlmesh/core/model/cache.py +4 -1
- sqlmesh/utils/cache.py +6 -1
- sqlmesh/utils/windows.py +14 -0
- {sqlmesh-0.184.3.dev11.dist-info → sqlmesh-0.184.3.dev13.dist-info}/METADATA +1 -1
- {sqlmesh-0.184.3.dev11.dist-info → sqlmesh-0.184.3.dev13.dist-info}/RECORD +16 -15
- web/server/api/endpoints/commands.py +12 -5
- web/server/api/endpoints/files.py +2 -2
- web/server/api/endpoints/models.py +2 -2
- web/server/models.py +1 -1
- web/server/utils.py +11 -0
- {sqlmesh-0.184.3.dev11.dist-info → sqlmesh-0.184.3.dev13.dist-info}/WHEEL +0 -0
- {sqlmesh-0.184.3.dev11.dist-info → sqlmesh-0.184.3.dev13.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.184.3.dev11.dist-info → sqlmesh-0.184.3.dev13.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.184.3.dev11.dist-info → sqlmesh-0.184.3.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.184.3.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 184, 3, '
|
|
20
|
+
__version__ = version = '0.184.3.dev13'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 184, 3, 'dev13')
|
|
@@ -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
|
|
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 =
|
|
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(
|
|
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(
|
sqlmesh/core/model/cache.py
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
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
|
sqlmesh/utils/windows.py
ADDED
|
@@ -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,5 +1,5 @@
|
|
|
1
1
|
sqlmesh/__init__.py,sha256=DRovDXI-9D9xeYDP7t8Fq7mI31S2btlN-LHPOK3y7PA,7240
|
|
2
|
-
sqlmesh/_version.py,sha256=
|
|
2
|
+
sqlmesh/_version.py,sha256=Hc_06dHlAjq77prp5p3D2QigzGLR41nO9X4XcV8MGwY,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=
|
|
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=
|
|
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=
|
|
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.
|
|
271
|
+
sqlmesh-0.184.3.dev13.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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
389
|
-
sqlmesh-0.184.3.
|
|
390
|
-
sqlmesh-0.184.3.
|
|
391
|
-
sqlmesh-0.184.3.
|
|
392
|
-
sqlmesh-0.184.3.
|
|
389
|
+
sqlmesh-0.184.3.dev13.dist-info/METADATA,sha256=x4qbulLqFAel_MrhyY2AJ8MLFuwvTktNSiHKXgfP0ZM,25499
|
|
390
|
+
sqlmesh-0.184.3.dev13.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
|
391
|
+
sqlmesh-0.184.3.dev13.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
|
|
392
|
+
sqlmesh-0.184.3.dev13.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
|
|
393
|
+
sqlmesh-0.184.3.dev13.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
|
|
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
|
|
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
|
|
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
|
|
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
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)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|