fakesnow 0.9.25__py3-none-any.whl → 0.9.27__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.
- fakesnow/cursor.py +4 -0
- fakesnow/info_schema.py +1 -1
- fakesnow/transforms.py +56 -35
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.27.dist-info}/METADATA +8 -8
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.27.dist-info}/RECORD +9 -9
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.27.dist-info}/WHEEL +1 -1
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.27.dist-info}/LICENSE +0 -0
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.27.dist-info}/entry_points.txt +0 -0
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.27.dist-info}/top_level.txt +0 -0
fakesnow/cursor.py
CHANGED
@@ -162,6 +162,7 @@ class FakeSnowflakeCursor:
|
|
162
162
|
.transform(transforms.extract_comment_on_columns)
|
163
163
|
.transform(transforms.information_schema_fs_columns_snowflake)
|
164
164
|
.transform(transforms.information_schema_fs_tables_ext)
|
165
|
+
.transform(transforms.information_schema_fs_views)
|
165
166
|
.transform(transforms.drop_schema_cascade)
|
166
167
|
.transform(transforms.tag)
|
167
168
|
.transform(transforms.semi_structured_types)
|
@@ -294,6 +295,9 @@ class FakeSnowflakeCursor:
|
|
294
295
|
(affected_count,) = self._duck_conn.fetchall()[0]
|
295
296
|
result_sql = SQL_DELETED_ROWS.substitute(count=affected_count)
|
296
297
|
|
298
|
+
elif cmd == "TRUNCATETABLE":
|
299
|
+
result_sql = SQL_SUCCESS
|
300
|
+
|
297
301
|
elif cmd in ("DESCRIBE TABLE", "DESCRIBE VIEW"):
|
298
302
|
# DESCRIBE TABLE/VIEW has already been run above to detect and error if the table exists
|
299
303
|
# We now rerun DESCRIBE TABLE/VIEW but transformed with columns to match Snowflake
|
fakesnow/info_schema.py
CHANGED
@@ -102,7 +102,7 @@ where catalog_name not in ('memory', 'system', 'temp', '_fs_global')
|
|
102
102
|
# replicates https://docs.snowflake.com/sql-reference/info-schema/views
|
103
103
|
SQL_CREATE_INFORMATION_SCHEMA_VIEWS_VIEW = Template(
|
104
104
|
"""
|
105
|
-
create view if not exists ${catalog}.information_schema.
|
105
|
+
create view if not exists ${catalog}.information_schema._fs_views AS
|
106
106
|
select
|
107
107
|
database_name as table_catalog,
|
108
108
|
schema_name as table_schema,
|
fakesnow/transforms.py
CHANGED
@@ -28,6 +28,8 @@ def alias_in_join(expression: exp.Expression) -> exp.Expression:
|
|
28
28
|
and (col := on.this)
|
29
29
|
and (isinstance(col, exp.Column))
|
30
30
|
and (alias := aliases.get(col.this))
|
31
|
+
# don't rewrite col with table identifier
|
32
|
+
and not col.table
|
31
33
|
):
|
32
34
|
col.args["this"] = alias.this
|
33
35
|
|
@@ -37,7 +39,7 @@ def alias_in_join(expression: exp.Expression) -> exp.Expression:
|
|
37
39
|
def alter_table_strip_cluster_by(expression: exp.Expression) -> exp.Expression:
|
38
40
|
"""Turn alter table cluster by into a no-op"""
|
39
41
|
if (
|
40
|
-
isinstance(expression, exp.
|
42
|
+
isinstance(expression, exp.Alter)
|
41
43
|
and (actions := expression.args.get("actions"))
|
42
44
|
and len(actions) == 1
|
43
45
|
and (isinstance(actions[0], exp.Cluster))
|
@@ -356,7 +358,7 @@ def extract_comment_on_columns(expression: exp.Expression) -> exp.Expression:
|
|
356
358
|
exp.Expression: The transformed expression, with any comment stored in the new 'table_comment' arg.
|
357
359
|
"""
|
358
360
|
|
359
|
-
if isinstance(expression, exp.
|
361
|
+
if isinstance(expression, exp.Alter) and (actions := expression.args.get("actions")):
|
360
362
|
new_actions: list[exp.Expression] = []
|
361
363
|
col_comments: list[tuple[str, str]] = []
|
362
364
|
for a in actions:
|
@@ -410,7 +412,7 @@ def extract_comment_on_table(expression: exp.Expression) -> exp.Expression:
|
|
410
412
|
new.args["table_comment"] = (table, cexp.this)
|
411
413
|
return new
|
412
414
|
elif (
|
413
|
-
isinstance(expression, exp.
|
415
|
+
isinstance(expression, exp.Alter)
|
414
416
|
and (sexp := expression.find(exp.AlterSet))
|
415
417
|
and (scp := sexp.find(exp.SchemaCommentProperty))
|
416
418
|
and isinstance(scp.this, exp.Literal)
|
@@ -436,7 +438,7 @@ def extract_text_length(expression: exp.Expression) -> exp.Expression:
|
|
436
438
|
exp.Expression: The original expression, with any text lengths stored in the new 'text_lengths' arg.
|
437
439
|
"""
|
438
440
|
|
439
|
-
if isinstance(expression, (exp.Create, exp.
|
441
|
+
if isinstance(expression, (exp.Create, exp.Alter)):
|
440
442
|
text_lengths = []
|
441
443
|
|
442
444
|
# exp.Select is for a ctas, exp.Schema is a plain definition
|
@@ -471,7 +473,6 @@ def flatten(expression: exp.Expression) -> exp.Expression:
|
|
471
473
|
|
472
474
|
See https://docs.snowflake.com/en/sql-reference/functions/flatten
|
473
475
|
|
474
|
-
TODO: return index.
|
475
476
|
TODO: support objects.
|
476
477
|
"""
|
477
478
|
if (
|
@@ -483,20 +484,34 @@ def flatten(expression: exp.Expression) -> exp.Expression:
|
|
483
484
|
):
|
484
485
|
explode_expression = expression.this.this.expression
|
485
486
|
|
486
|
-
|
487
|
-
this=
|
487
|
+
value = exp.Cast(
|
488
|
+
this=explode_expression,
|
489
|
+
to=exp.DataType(
|
490
|
+
this=exp.DataType.Type.ARRAY,
|
491
|
+
expressions=[exp.DataType(this=exp.DataType.Type.JSON, nested=False, prefix=False)],
|
492
|
+
nested=True,
|
493
|
+
),
|
494
|
+
)
|
495
|
+
|
496
|
+
return exp.Subquery(
|
497
|
+
this=exp.Select(
|
488
498
|
expressions=[
|
489
|
-
exp.
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
499
|
+
exp.Unnest(
|
500
|
+
expressions=[value],
|
501
|
+
alias=exp.Identifier(this="VALUE", quoted=False),
|
502
|
+
),
|
503
|
+
exp.Alias(
|
504
|
+
this=exp.Sub(
|
505
|
+
this=exp.Anonymous(
|
506
|
+
this="generate_subscripts", expressions=[value, exp.Literal(this="1", is_string=False)]
|
507
|
+
),
|
508
|
+
expression=exp.Literal(this="1", is_string=False),
|
495
509
|
),
|
496
|
-
|
510
|
+
alias=exp.Identifier(this="INDEX", quoted=False),
|
511
|
+
),
|
497
512
|
],
|
498
513
|
),
|
499
|
-
alias=exp.TableAlias(this=alias.this
|
514
|
+
alias=exp.TableAlias(this=alias.this),
|
500
515
|
)
|
501
516
|
|
502
517
|
return expression
|
@@ -622,6 +637,20 @@ def information_schema_fs_tables_ext(expression: exp.Expression) -> exp.Expressi
|
|
622
637
|
return expression
|
623
638
|
|
624
639
|
|
640
|
+
def information_schema_fs_views(expression: exp.Expression) -> exp.Expression:
|
641
|
+
"""Use information_schema._fs_views to return Snowflake's version instead of duckdb's."""
|
642
|
+
|
643
|
+
if (
|
644
|
+
isinstance(expression, exp.Select)
|
645
|
+
and (tbl_exp := expression.find(exp.Table))
|
646
|
+
and tbl_exp.name.upper() == "VIEWS"
|
647
|
+
and tbl_exp.db.upper() == "INFORMATION_SCHEMA"
|
648
|
+
):
|
649
|
+
tbl_exp.set("this", exp.Identifier(this="_FS_VIEWS", quoted=False))
|
650
|
+
|
651
|
+
return expression
|
652
|
+
|
653
|
+
|
625
654
|
def integer_precision(expression: exp.Expression) -> exp.Expression:
|
626
655
|
"""Convert integers to bigint.
|
627
656
|
|
@@ -631,8 +660,7 @@ def integer_precision(expression: exp.Expression) -> exp.Expression:
|
|
631
660
|
if (
|
632
661
|
isinstance(expression, exp.DataType)
|
633
662
|
and (expression.this == exp.DataType.Type.DECIMAL and not expression.expressions)
|
634
|
-
|
635
|
-
):
|
663
|
+
) or expression.this in (exp.DataType.Type.INT, exp.DataType.Type.SMALLINT, exp.DataType.Type.TINYINT):
|
636
664
|
return exp.DataType(
|
637
665
|
this=exp.DataType.Type.BIGINT,
|
638
666
|
nested=False,
|
@@ -707,8 +735,8 @@ def random(expression: exp.Expression) -> exp.Expression:
|
|
707
735
|
new_rand = exp.Cast(
|
708
736
|
this=exp.Paren(
|
709
737
|
this=exp.Mul(
|
710
|
-
this=exp.Paren(this=exp.Sub(this=exp.Rand(), expression=exp.Literal(this=0.5, is_string=False))),
|
711
|
-
expression=exp.Literal(this=9223372036854775807, is_string=False),
|
738
|
+
this=exp.Paren(this=exp.Sub(this=exp.Rand(), expression=exp.Literal(this="0.5", is_string=False))),
|
739
|
+
expression=exp.Literal(this="9223372036854775807", is_string=False),
|
712
740
|
)
|
713
741
|
),
|
714
742
|
to=exp.DataType(this=exp.DataType.Type.BIGINT, nested=False, prefix=False),
|
@@ -809,31 +837,24 @@ def regex_substr(expression: exp.Expression) -> exp.Expression:
|
|
809
837
|
pattern.args["this"] = pattern.this.replace("\\\\", "\\")
|
810
838
|
|
811
839
|
# number of characters from the beginning of the string where the function starts searching for matches
|
812
|
-
|
813
|
-
position = expression.args["position"]
|
814
|
-
except KeyError:
|
815
|
-
position = exp.Literal(this="1", is_string=False)
|
840
|
+
position = expression.args["position"] or exp.Literal(this="1", is_string=False)
|
816
841
|
|
817
842
|
# which occurrence of the pattern to match
|
818
|
-
|
819
|
-
|
820
|
-
except KeyError:
|
821
|
-
occurrence = 1
|
843
|
+
occurrence = expression.args["occurrence"]
|
844
|
+
occurrence = int(occurrence.this) if occurrence else 1
|
822
845
|
|
823
846
|
# the duckdb dialect increments bracket (ie: index) expressions by 1 because duckdb is 1-indexed,
|
824
847
|
# so we need to compensate by subtracting 1
|
825
848
|
occurrence = exp.Literal(this=str(occurrence - 1), is_string=False)
|
826
849
|
|
827
|
-
|
828
|
-
regex_parameters_value = str(expression.args["parameters"].this)
|
850
|
+
if parameters := expression.args["parameters"]:
|
829
851
|
# 'e' parameter doesn't make sense for duckdb
|
830
|
-
regex_parameters = exp.Literal(this=
|
831
|
-
|
852
|
+
regex_parameters = exp.Literal(this=parameters.this.replace("e", ""), is_string=True)
|
853
|
+
else:
|
832
854
|
regex_parameters = exp.Literal(is_string=True)
|
833
855
|
|
834
|
-
|
835
|
-
|
836
|
-
except KeyError:
|
856
|
+
group_num = expression.args["group"]
|
857
|
+
if not group_num:
|
837
858
|
if isinstance(regex_parameters.this, str) and "e" in regex_parameters.this:
|
838
859
|
group_num = exp.Literal(this="1", is_string=False)
|
839
860
|
else:
|
@@ -1023,7 +1044,7 @@ def tag(expression: exp.Expression) -> exp.Expression:
|
|
1023
1044
|
exp.Expression: The transformed expression.
|
1024
1045
|
"""
|
1025
1046
|
|
1026
|
-
if isinstance(expression, exp.
|
1047
|
+
if isinstance(expression, exp.Alter) and (actions := expression.args.get("actions")):
|
1027
1048
|
for a in actions:
|
1028
1049
|
if isinstance(a, exp.AlterSet) and a.args.get("tag"):
|
1029
1050
|
return SUCCESS_NOP
|
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fakesnow
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.27
|
4
4
|
Summary: Fake Snowflake Connector for Python. Run, mock and test Snowflake DB locally.
|
5
|
-
License:
|
5
|
+
License: Apache License
|
6
6
|
Version 2.0, January 2004
|
7
7
|
http://www.apache.org/licenses/
|
8
8
|
|
@@ -210,22 +210,22 @@ Classifier: License :: OSI Approved :: MIT License
|
|
210
210
|
Requires-Python: >=3.9
|
211
211
|
Description-Content-Type: text/markdown
|
212
212
|
License-File: LICENSE
|
213
|
-
Requires-Dist: duckdb~=1.
|
213
|
+
Requires-Dist: duckdb~=1.1.3
|
214
214
|
Requires-Dist: pyarrow
|
215
215
|
Requires-Dist: snowflake-connector-python
|
216
|
-
Requires-Dist: sqlglot~=25.
|
216
|
+
Requires-Dist: sqlglot~=25.34.0
|
217
217
|
Provides-Extra: dev
|
218
218
|
Requires-Dist: build~=1.0; extra == "dev"
|
219
219
|
Requires-Dist: dirty-equals; extra == "dev"
|
220
220
|
Requires-Dist: pandas-stubs; extra == "dev"
|
221
221
|
Requires-Dist: snowflake-connector-python[pandas,secure-local-storage]; extra == "dev"
|
222
|
-
Requires-Dist: pre-commit~=
|
222
|
+
Requires-Dist: pre-commit~=4.0; extra == "dev"
|
223
223
|
Requires-Dist: pyarrow-stubs==10.0.1.9; extra == "dev"
|
224
224
|
Requires-Dist: pytest~=8.0; extra == "dev"
|
225
225
|
Requires-Dist: pytest-asyncio; extra == "dev"
|
226
|
-
Requires-Dist: ruff~=0.
|
227
|
-
Requires-Dist: twine~=
|
228
|
-
Requires-Dist: snowflake-sqlalchemy~=1.
|
226
|
+
Requires-Dist: ruff~=0.8.1; extra == "dev"
|
227
|
+
Requires-Dist: twine~=6.0; extra == "dev"
|
228
|
+
Requires-Dist: snowflake-sqlalchemy~=1.7.0; extra == "dev"
|
229
229
|
Provides-Extra: notebook
|
230
230
|
Requires-Dist: duckdb-engine; extra == "notebook"
|
231
231
|
Requires-Dist: ipykernel; extra == "notebook"
|
@@ -4,23 +4,23 @@ fakesnow/arrow.py,sha256=EGAYeuCnRuvmWBEGqw2YOcgQR4zcCsZBu85kSRl70dQ,4698
|
|
4
4
|
fakesnow/checks.py,sha256=N8sXldhS3u1gG32qvZ4VFlsKgavRKrQrxLiQU8am1lw,2691
|
5
5
|
fakesnow/cli.py,sha256=9qfI-Ssr6mo8UmIlXkUAOz2z2YPBgDsrEVaZv9FjGFs,2201
|
6
6
|
fakesnow/conn.py,sha256=Gy_Z7BZRm5yMjV3x6hR4iegDQFdG9aJBjqWdc3iWYFU,5353
|
7
|
-
fakesnow/cursor.py,sha256=
|
7
|
+
fakesnow/cursor.py,sha256=8wWtRCxzrM1yiHmH2C-9CT0b98nTzr23ygeaEAkumRE,20086
|
8
8
|
fakesnow/expr.py,sha256=CAxuYIUkwI339DQIBzvFF0F-m1tcVGKEPA5rDTzmH9A,892
|
9
9
|
fakesnow/fakes.py,sha256=JQTiUkkwPeQrJ8FDWhPFPK6pGwd_aR2oiOrNzCWznlM,187
|
10
10
|
fakesnow/fixtures.py,sha256=G-NkVeruSQAJ7fvSS2fR2oysUn0Yra1pohHlOvacKEk,455
|
11
|
-
fakesnow/info_schema.py,sha256=
|
11
|
+
fakesnow/info_schema.py,sha256=nsDceFtjiSXrvkksKziVvqrefskaSyOmAspBwMAsaDg,6307
|
12
12
|
fakesnow/instance.py,sha256=3cJvPRuFy19dMKXbtBLl6imzO48pEw8uTYhZyFDuwhk,3133
|
13
13
|
fakesnow/macros.py,sha256=pX1YJDnQOkFJSHYUjQ6ErEkYIKvFI6Ncz_au0vv1csA,265
|
14
14
|
fakesnow/pandas_tools.py,sha256=WjyjTV8QUCQQaCGboaEOvx2uo4BkknpWYjtLwkeCY6U,3468
|
15
15
|
fakesnow/py.typed,sha256=B-DLSjYBi7pkKjwxCSdpVj2J02wgfJr-E7B1wOUyxYU,80
|
16
16
|
fakesnow/server.py,sha256=SO5xKZ4rvySsuKDsoSPSCZcFuIX_K7d1XJYhRRJ-7Bk,4150
|
17
|
-
fakesnow/transforms.py,sha256=
|
17
|
+
fakesnow/transforms.py,sha256=h35WHWxhlXpfe03f3FCF64QVmiCLMdDZF7oZmaAOS60,55451
|
18
18
|
fakesnow/transforms_merge.py,sha256=7rq-UPjfFNRrFsqR8xx3otwP6-k4eslLVLhfuqSXq1A,8314
|
19
19
|
fakesnow/types.py,sha256=9Tt83Z7ctc9_v6SYyayXYz4MEI4RZo4zq_uqdj4g3Dk,2681
|
20
20
|
fakesnow/variables.py,sha256=WXyPnkeNwD08gy52yF66CVe2twiYC50tztNfgXV4q1k,3032
|
21
|
-
fakesnow-0.9.
|
22
|
-
fakesnow-0.9.
|
23
|
-
fakesnow-0.9.
|
24
|
-
fakesnow-0.9.
|
25
|
-
fakesnow-0.9.
|
26
|
-
fakesnow-0.9.
|
21
|
+
fakesnow-0.9.27.dist-info/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
|
22
|
+
fakesnow-0.9.27.dist-info/METADATA,sha256=k7PwECuxM55u-Dx_WyieDaH1p2BrHlcmu9INMsxGtzQ,18108
|
23
|
+
fakesnow-0.9.27.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
24
|
+
fakesnow-0.9.27.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
|
25
|
+
fakesnow-0.9.27.dist-info/top_level.txt,sha256=500evXI1IFX9so82cizGIEMHAb_dJNPaZvd2H9dcKTA,24
|
26
|
+
fakesnow-0.9.27.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|