fakesnow 0.9.9__tar.gz → 0.9.11__tar.gz

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.
Files changed (32) hide show
  1. {fakesnow-0.9.9 → fakesnow-0.9.11}/PKG-INFO +3 -3
  2. {fakesnow-0.9.9 → fakesnow-0.9.11}/README.md +1 -1
  3. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/fakes.py +7 -1
  4. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/transforms.py +21 -0
  5. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow.egg-info/PKG-INFO +3 -3
  6. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow.egg-info/requires.txt +1 -1
  7. {fakesnow-0.9.9 → fakesnow-0.9.11}/pyproject.toml +2 -2
  8. {fakesnow-0.9.9 → fakesnow-0.9.11}/tests/test_fakes.py +30 -0
  9. {fakesnow-0.9.9 → fakesnow-0.9.11}/tests/test_transforms.py +8 -0
  10. {fakesnow-0.9.9 → fakesnow-0.9.11}/LICENSE +0 -0
  11. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/__init__.py +0 -0
  12. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/__main__.py +0 -0
  13. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/checks.py +0 -0
  14. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/cli.py +0 -0
  15. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/expr.py +0 -0
  16. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/fixtures.py +0 -0
  17. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/global_database.py +0 -0
  18. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/info_schema.py +0 -0
  19. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/macros.py +0 -0
  20. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow/py.typed +0 -0
  21. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow.egg-info/SOURCES.txt +0 -0
  22. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow.egg-info/dependency_links.txt +0 -0
  23. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow.egg-info/entry_points.txt +0 -0
  24. {fakesnow-0.9.9 → fakesnow-0.9.11}/fakesnow.egg-info/top_level.txt +0 -0
  25. {fakesnow-0.9.9 → fakesnow-0.9.11}/setup.cfg +0 -0
  26. {fakesnow-0.9.9 → fakesnow-0.9.11}/tests/test_checks.py +0 -0
  27. {fakesnow-0.9.9 → fakesnow-0.9.11}/tests/test_cli.py +0 -0
  28. {fakesnow-0.9.9 → fakesnow-0.9.11}/tests/test_expr.py +0 -0
  29. {fakesnow-0.9.9 → fakesnow-0.9.11}/tests/test_info_schema.py +0 -0
  30. {fakesnow-0.9.9 → fakesnow-0.9.11}/tests/test_patch.py +0 -0
  31. {fakesnow-0.9.9 → fakesnow-0.9.11}/tests/test_sqlalchemy.py +0 -0
  32. {fakesnow-0.9.9 → fakesnow-0.9.11}/tests/test_users.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fakesnow
3
- Version: 0.9.9
3
+ Version: 0.9.11
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
@@ -220,7 +220,7 @@ Requires-Dist: pandas-stubs; extra == "dev"
220
220
  Requires-Dist: snowflake-connector-python[pandas,secure-local-storage]; extra == "dev"
221
221
  Requires-Dist: pre-commit~=3.4; extra == "dev"
222
222
  Requires-Dist: pytest~=8.0; extra == "dev"
223
- Requires-Dist: ruff~=0.3.2; extra == "dev"
223
+ Requires-Dist: ruff~=0.4.2; extra == "dev"
224
224
  Requires-Dist: twine~=5.0; extra == "dev"
225
225
  Requires-Dist: snowflake-sqlalchemy~=1.5.0; extra == "dev"
226
226
  Provides-Extra: notebook
@@ -357,7 +357,7 @@ For more detail see [tests/test_fakes.py](tests/test_fakes.py)
357
357
  ## Caveats
358
358
 
359
359
  - The order of rows is non deterministic and may not match Snowflake unless ORDER BY is fully specified.
360
- - A more liberal Snowflake SQL dialect than a real Snowflake instance is supported, ie: some queries might pass using fakesnow that a real Snowflake instance would reject.
360
+ - A more liberal Snowflake SQL dialect than used by a real Snowflake instance is supported, ie: some queries might pass using fakesnow that a real Snowflake instance would reject.
361
361
 
362
362
  ## Contributing
363
363
 
@@ -127,7 +127,7 @@ For more detail see [tests/test_fakes.py](tests/test_fakes.py)
127
127
  ## Caveats
128
128
 
129
129
  - The order of rows is non deterministic and may not match Snowflake unless ORDER BY is fully specified.
130
- - A more liberal Snowflake SQL dialect than a real Snowflake instance is supported, ie: some queries might pass using fakesnow that a real Snowflake instance would reject.
130
+ - A more liberal Snowflake SQL dialect than used by a real Snowflake instance is supported, ie: some queries might pass using fakesnow that a real Snowflake instance would reject.
131
131
 
132
132
  ## Contributing
133
133
 
@@ -193,6 +193,7 @@ class FakeSnowflakeCursor:
193
193
  .transform(transforms.show_users)
194
194
  .transform(transforms.create_user)
195
195
  .transform(transforms.sha256)
196
+ .transform(transforms.create_clone)
196
197
  )
197
198
 
198
199
  def _execute(
@@ -629,7 +630,12 @@ class FakeSnowflakeConnection:
629
630
  df[col] = df[col].apply(lambda x: json.dumps(x) if isinstance(x, (dict, list)) else x)
630
631
 
631
632
  escaped_cols = ",".join(f'"{col}"' for col in df.columns.to_list())
632
- self._duck_conn.execute(f"INSERT INTO {table_name}({escaped_cols}) SELECT * FROM df")
633
+ name = table_name
634
+ if schema:
635
+ table_name = f"{schema}.{table_name}"
636
+ if database:
637
+ name = f"{database}.{table_name}"
638
+ self._duck_conn.execute(f"INSERT INTO {name}({escaped_cols}) SELECT * FROM df")
633
639
 
634
640
  return self._duck_conn.fetchall()[0][0]
635
641
 
@@ -55,6 +55,27 @@ def array_agg_within_group(expression: exp.Expression) -> exp.Expression:
55
55
  return expression
56
56
 
57
57
 
58
+ def create_clone(expression: exp.Expression) -> exp.Expression:
59
+ """Transform create table clone to create table as select."""
60
+
61
+ if (
62
+ isinstance(expression, exp.Create)
63
+ and str(expression.args.get("kind")).upper() == "TABLE"
64
+ and (clone := expression.find(exp.Clone))
65
+ ):
66
+ return exp.Create(
67
+ this=expression.this,
68
+ kind="TABLE",
69
+ expression=exp.Select(
70
+ expressions=[
71
+ exp.Star(),
72
+ ],
73
+ **{"from": exp.From(this=clone.this)},
74
+ ),
75
+ )
76
+ return expression
77
+
78
+
58
79
  # TODO: move this into a Dialect as a transpilation
59
80
  def create_database(expression: exp.Expression, db_path: Path | None = None) -> exp.Expression:
60
81
  """Transform create database to attach database.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fakesnow
3
- Version: 0.9.9
3
+ Version: 0.9.11
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
@@ -220,7 +220,7 @@ Requires-Dist: pandas-stubs; extra == "dev"
220
220
  Requires-Dist: snowflake-connector-python[pandas,secure-local-storage]; extra == "dev"
221
221
  Requires-Dist: pre-commit~=3.4; extra == "dev"
222
222
  Requires-Dist: pytest~=8.0; extra == "dev"
223
- Requires-Dist: ruff~=0.3.2; extra == "dev"
223
+ Requires-Dist: ruff~=0.4.2; extra == "dev"
224
224
  Requires-Dist: twine~=5.0; extra == "dev"
225
225
  Requires-Dist: snowflake-sqlalchemy~=1.5.0; extra == "dev"
226
226
  Provides-Extra: notebook
@@ -357,7 +357,7 @@ For more detail see [tests/test_fakes.py](tests/test_fakes.py)
357
357
  ## Caveats
358
358
 
359
359
  - The order of rows is non deterministic and may not match Snowflake unless ORDER BY is fully specified.
360
- - A more liberal Snowflake SQL dialect than a real Snowflake instance is supported, ie: some queries might pass using fakesnow that a real Snowflake instance would reject.
360
+ - A more liberal Snowflake SQL dialect than used by a real Snowflake instance is supported, ie: some queries might pass using fakesnow that a real Snowflake instance would reject.
361
361
 
362
362
  ## Contributing
363
363
 
@@ -9,7 +9,7 @@ pandas-stubs
9
9
  snowflake-connector-python[pandas,secure-local-storage]
10
10
  pre-commit~=3.4
11
11
  pytest~=8.0
12
- ruff~=0.3.2
12
+ ruff~=0.4.2
13
13
  twine~=5.0
14
14
  snowflake-sqlalchemy~=1.5.0
15
15
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "fakesnow"
3
3
  description = "Fake Snowflake Connector for Python. Run, mock and test Snowflake DB locally."
4
- version = "0.9.9"
4
+ version = "0.9.11"
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
7
7
  classifiers = ["License :: OSI Approved :: MIT License"]
@@ -29,7 +29,7 @@ dev = [
29
29
  "snowflake-connector-python[pandas, secure-local-storage]",
30
30
  "pre-commit~=3.4",
31
31
  "pytest~=8.0",
32
- "ruff~=0.3.2",
32
+ "ruff~=0.4.2",
33
33
  "twine~=5.0",
34
34
  "snowflake-sqlalchemy~=1.5.0",
35
35
  ]
@@ -110,6 +110,16 @@ def test_binding_qmark(_fakesnow: None):
110
110
  cur.execute("select * from customers where id = ?", (1,))
111
111
 
112
112
 
113
+ def test_clone(cur: snowflake.connector.cursor.SnowflakeCursor):
114
+ cur.execute("create table customers (ID int, FIRST_NAME varchar, ACTIVE boolean)")
115
+ cur.execute("insert into customers values (1, 'Jenny', True)")
116
+
117
+ cur.execute("create table customers2 clone db1.schema1.customers")
118
+ cur.execute("select * from customers2")
119
+ # TODO check tags are copied too
120
+ assert cur.fetchall() == [(1, "Jenny", True)]
121
+
122
+
113
123
  def test_close_conn(conn: snowflake.connector.SnowflakeConnection, cur: snowflake.connector.cursor.SnowflakeCursor):
114
124
  conn.close()
115
125
  with pytest.raises(snowflake.connector.errors.DatabaseError) as excinfo:
@@ -1601,6 +1611,26 @@ def test_write_pandas_dict_different_keys(conn: snowflake.connector.SnowflakeCon
1601
1611
  assert indent(cur.fetchall()) == [('{\n "k": "v1"\n}',), ('{\n "k2": [\n "v\'2",\n "v\\"3"\n ]\n}',)]
1602
1612
 
1603
1613
 
1614
+ def test_write_pandas_db_schema(conn: snowflake.connector.SnowflakeConnection):
1615
+ with conn.cursor() as cur:
1616
+ cur.execute("create database db2")
1617
+ cur.execute("create schema db2.schema2")
1618
+ cur.execute("create or replace table db2.schema2.customers (ID int, FIRST_NAME varchar, LAST_NAME varchar)")
1619
+
1620
+ df = pd.DataFrame.from_records(
1621
+ [
1622
+ {"ID": 1, "FIRST_NAME": "Jenny"},
1623
+ {"ID": 2, "FIRST_NAME": "Jasper"},
1624
+ ]
1625
+ )
1626
+ snowflake.connector.pandas_tools.write_pandas(conn, df, "CUSTOMERS", "DB2", "SCHEMA2")
1627
+
1628
+ cur.execute("select id, first_name, last_name from db2.schema2.customers")
1629
+
1630
+ # columns not in dataframe will receive their default value
1631
+ assert cur.fetchall() == [(1, "Jenny", None), (2, "Jasper", None)]
1632
+
1633
+
1604
1634
  def indent(rows: Sequence[tuple] | Sequence[dict]) -> list[tuple]:
1605
1635
  # indent duckdb json strings tuple values to match snowflake json strings
1606
1636
  assert isinstance(rows[0], tuple)
@@ -9,6 +9,7 @@ from fakesnow.transforms import (
9
9
  _get_to_number_args,
10
10
  array_agg_within_group,
11
11
  array_size,
12
+ create_clone,
12
13
  create_database,
13
14
  dateadd_date_cast,
14
15
  dateadd_string_literal_timestamp_cast,
@@ -84,6 +85,13 @@ def test_array_agg_within_group() -> None:
84
85
  )
85
86
 
86
87
 
88
+ def test_create_clone() -> None:
89
+ assert (
90
+ sqlglot.parse_one("create table customers2 clone db1.schema1.customer").transform(create_clone).sql()
91
+ == "CREATE TABLE customers2 AS SELECT * FROM db1.schema1.customer"
92
+ )
93
+
94
+
87
95
  def test_create_database() -> None:
88
96
  e = sqlglot.parse_one("create database foobar").transform(create_database)
89
97
  assert e.sql() == "ATTACH DATABASE ':memory:' AS foobar"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes