fakesnow 0.9.25__py3-none-any.whl → 0.9.26__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 +53 -33
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.26.dist-info}/METADATA +6 -6
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.26.dist-info}/RECORD +9 -9
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.26.dist-info}/WHEEL +1 -1
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.26.dist-info}/LICENSE +0 -0
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.26.dist-info}/entry_points.txt +0 -0
- {fakesnow-0.9.25.dist-info → fakesnow-0.9.26.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
@@ -37,7 +37,7 @@ def alias_in_join(expression: exp.Expression) -> exp.Expression:
|
|
37
37
|
def alter_table_strip_cluster_by(expression: exp.Expression) -> exp.Expression:
|
38
38
|
"""Turn alter table cluster by into a no-op"""
|
39
39
|
if (
|
40
|
-
isinstance(expression, exp.
|
40
|
+
isinstance(expression, exp.Alter)
|
41
41
|
and (actions := expression.args.get("actions"))
|
42
42
|
and len(actions) == 1
|
43
43
|
and (isinstance(actions[0], exp.Cluster))
|
@@ -356,7 +356,7 @@ def extract_comment_on_columns(expression: exp.Expression) -> exp.Expression:
|
|
356
356
|
exp.Expression: The transformed expression, with any comment stored in the new 'table_comment' arg.
|
357
357
|
"""
|
358
358
|
|
359
|
-
if isinstance(expression, exp.
|
359
|
+
if isinstance(expression, exp.Alter) and (actions := expression.args.get("actions")):
|
360
360
|
new_actions: list[exp.Expression] = []
|
361
361
|
col_comments: list[tuple[str, str]] = []
|
362
362
|
for a in actions:
|
@@ -410,7 +410,7 @@ def extract_comment_on_table(expression: exp.Expression) -> exp.Expression:
|
|
410
410
|
new.args["table_comment"] = (table, cexp.this)
|
411
411
|
return new
|
412
412
|
elif (
|
413
|
-
isinstance(expression, exp.
|
413
|
+
isinstance(expression, exp.Alter)
|
414
414
|
and (sexp := expression.find(exp.AlterSet))
|
415
415
|
and (scp := sexp.find(exp.SchemaCommentProperty))
|
416
416
|
and isinstance(scp.this, exp.Literal)
|
@@ -436,7 +436,7 @@ def extract_text_length(expression: exp.Expression) -> exp.Expression:
|
|
436
436
|
exp.Expression: The original expression, with any text lengths stored in the new 'text_lengths' arg.
|
437
437
|
"""
|
438
438
|
|
439
|
-
if isinstance(expression, (exp.Create, exp.
|
439
|
+
if isinstance(expression, (exp.Create, exp.Alter)):
|
440
440
|
text_lengths = []
|
441
441
|
|
442
442
|
# exp.Select is for a ctas, exp.Schema is a plain definition
|
@@ -471,7 +471,6 @@ def flatten(expression: exp.Expression) -> exp.Expression:
|
|
471
471
|
|
472
472
|
See https://docs.snowflake.com/en/sql-reference/functions/flatten
|
473
473
|
|
474
|
-
TODO: return index.
|
475
474
|
TODO: support objects.
|
476
475
|
"""
|
477
476
|
if (
|
@@ -483,20 +482,34 @@ def flatten(expression: exp.Expression) -> exp.Expression:
|
|
483
482
|
):
|
484
483
|
explode_expression = expression.this.this.expression
|
485
484
|
|
486
|
-
|
487
|
-
this=
|
485
|
+
value = exp.Cast(
|
486
|
+
this=explode_expression,
|
487
|
+
to=exp.DataType(
|
488
|
+
this=exp.DataType.Type.ARRAY,
|
489
|
+
expressions=[exp.DataType(this=exp.DataType.Type.JSON, nested=False, prefix=False)],
|
490
|
+
nested=True,
|
491
|
+
),
|
492
|
+
)
|
493
|
+
|
494
|
+
return exp.Subquery(
|
495
|
+
this=exp.Select(
|
488
496
|
expressions=[
|
489
|
-
exp.
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
497
|
+
exp.Unnest(
|
498
|
+
expressions=[value],
|
499
|
+
alias=exp.Identifier(this="VALUE", quoted=False),
|
500
|
+
),
|
501
|
+
exp.Alias(
|
502
|
+
this=exp.Sub(
|
503
|
+
this=exp.Anonymous(
|
504
|
+
this="generate_subscripts", expressions=[value, exp.Literal(this="1", is_string=False)]
|
505
|
+
),
|
506
|
+
expression=exp.Literal(this="1", is_string=False),
|
495
507
|
),
|
496
|
-
|
508
|
+
alias=exp.Identifier(this="INDEX", quoted=False),
|
509
|
+
),
|
497
510
|
],
|
498
511
|
),
|
499
|
-
alias=exp.TableAlias(this=alias.this
|
512
|
+
alias=exp.TableAlias(this=alias.this),
|
500
513
|
)
|
501
514
|
|
502
515
|
return expression
|
@@ -622,6 +635,20 @@ def information_schema_fs_tables_ext(expression: exp.Expression) -> exp.Expressi
|
|
622
635
|
return expression
|
623
636
|
|
624
637
|
|
638
|
+
def information_schema_fs_views(expression: exp.Expression) -> exp.Expression:
|
639
|
+
"""Use information_schema._fs_views to return Snowflake's version instead of duckdb's."""
|
640
|
+
|
641
|
+
if (
|
642
|
+
isinstance(expression, exp.Select)
|
643
|
+
and (tbl_exp := expression.find(exp.Table))
|
644
|
+
and tbl_exp.name.upper() == "VIEWS"
|
645
|
+
and tbl_exp.db.upper() == "INFORMATION_SCHEMA"
|
646
|
+
):
|
647
|
+
tbl_exp.set("this", exp.Identifier(this="_FS_VIEWS", quoted=False))
|
648
|
+
|
649
|
+
return expression
|
650
|
+
|
651
|
+
|
625
652
|
def integer_precision(expression: exp.Expression) -> exp.Expression:
|
626
653
|
"""Convert integers to bigint.
|
627
654
|
|
@@ -707,8 +734,8 @@ def random(expression: exp.Expression) -> exp.Expression:
|
|
707
734
|
new_rand = exp.Cast(
|
708
735
|
this=exp.Paren(
|
709
736
|
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),
|
737
|
+
this=exp.Paren(this=exp.Sub(this=exp.Rand(), expression=exp.Literal(this="0.5", is_string=False))),
|
738
|
+
expression=exp.Literal(this="9223372036854775807", is_string=False),
|
712
739
|
)
|
713
740
|
),
|
714
741
|
to=exp.DataType(this=exp.DataType.Type.BIGINT, nested=False, prefix=False),
|
@@ -809,31 +836,24 @@ def regex_substr(expression: exp.Expression) -> exp.Expression:
|
|
809
836
|
pattern.args["this"] = pattern.this.replace("\\\\", "\\")
|
810
837
|
|
811
838
|
# 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)
|
839
|
+
position = expression.args["position"] or exp.Literal(this="1", is_string=False)
|
816
840
|
|
817
841
|
# which occurrence of the pattern to match
|
818
|
-
|
819
|
-
|
820
|
-
except KeyError:
|
821
|
-
occurrence = 1
|
842
|
+
occurrence = expression.args["occurrence"]
|
843
|
+
occurrence = int(occurrence.this) if occurrence else 1
|
822
844
|
|
823
845
|
# the duckdb dialect increments bracket (ie: index) expressions by 1 because duckdb is 1-indexed,
|
824
846
|
# so we need to compensate by subtracting 1
|
825
847
|
occurrence = exp.Literal(this=str(occurrence - 1), is_string=False)
|
826
848
|
|
827
|
-
|
828
|
-
regex_parameters_value = str(expression.args["parameters"].this)
|
849
|
+
if parameters := expression.args["parameters"]:
|
829
850
|
# 'e' parameter doesn't make sense for duckdb
|
830
|
-
regex_parameters = exp.Literal(this=
|
831
|
-
|
851
|
+
regex_parameters = exp.Literal(this=parameters.this.replace("e", ""), is_string=True)
|
852
|
+
else:
|
832
853
|
regex_parameters = exp.Literal(is_string=True)
|
833
854
|
|
834
|
-
|
835
|
-
|
836
|
-
except KeyError:
|
855
|
+
group_num = expression.args["group"]
|
856
|
+
if not group_num:
|
837
857
|
if isinstance(regex_parameters.this, str) and "e" in regex_parameters.this:
|
838
858
|
group_num = exp.Literal(this="1", is_string=False)
|
839
859
|
else:
|
@@ -1023,7 +1043,7 @@ def tag(expression: exp.Expression) -> exp.Expression:
|
|
1023
1043
|
exp.Expression: The transformed expression.
|
1024
1044
|
"""
|
1025
1045
|
|
1026
|
-
if isinstance(expression, exp.
|
1046
|
+
if isinstance(expression, exp.Alter) and (actions := expression.args.get("actions")):
|
1027
1047
|
for a in actions:
|
1028
1048
|
if isinstance(a, exp.AlterSet) and a.args.get("tag"):
|
1029
1049
|
return SUCCESS_NOP
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fakesnow
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.26
|
4
4
|
Summary: Fake Snowflake Connector for Python. Run, mock and test Snowflake DB locally.
|
5
5
|
License: Apache License
|
6
6
|
Version 2.0, January 2004
|
@@ -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.24.1
|
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.
|
226
|
+
Requires-Dist: ruff~=0.7.2; extra == "dev"
|
227
227
|
Requires-Dist: twine~=5.0; extra == "dev"
|
228
|
-
Requires-Dist: snowflake-sqlalchemy~=1.
|
228
|
+
Requires-Dist: snowflake-sqlalchemy~=1.6.1; 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=VFLA5Fc1i4FuiVdvUuDrK-kA2caqiT8Gw9btMDPJhRA,55367
|
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.26.dist-info/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
|
22
|
+
fakesnow-0.9.26.dist-info/METADATA,sha256=92zIwzq7FP-BrfhUcKbdbqYs0eqN9TCKvT_NVdEKZTI,18075
|
23
|
+
fakesnow-0.9.26.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
|
24
|
+
fakesnow-0.9.26.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
|
25
|
+
fakesnow-0.9.26.dist-info/top_level.txt,sha256=500evXI1IFX9so82cizGIEMHAb_dJNPaZvd2H9dcKTA,24
|
26
|
+
fakesnow-0.9.26.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|