fakesnow 0.9.4__py3-none-any.whl → 0.9.6__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/__init__.py CHANGED
@@ -85,6 +85,7 @@ def patch(
85
85
  p = mock.patch(im, side_effect=fake)
86
86
  stack.enter_context(p)
87
87
 
88
- yield None
89
-
90
- stack.close()
88
+ try:
89
+ yield None
90
+ finally:
91
+ stack.close()
fakesnow/fakes.py CHANGED
@@ -37,6 +37,7 @@ SQL_SUCCESS = "SELECT 'Statement executed successfully.' as 'status'"
37
37
  SQL_CREATED_DATABASE = Template("SELECT 'Database ${name} successfully created.' as 'status'")
38
38
  SQL_CREATED_SCHEMA = Template("SELECT 'Schema ${name} successfully created.' as 'status'")
39
39
  SQL_CREATED_TABLE = Template("SELECT 'Table ${name} successfully created.' as 'status'")
40
+ SQL_CREATED_VIEW = Template("SELECT 'View ${name} successfully created.' as 'status'")
40
41
  SQL_DROPPED = Template("SELECT '${name} successfully dropped.' as 'status'")
41
42
  SQL_INSERTED_ROWS = Template("SELECT ${count} as 'number of rows inserted'")
42
43
  SQL_UPDATED_ROWS = Template("SELECT ${count} as 'number of rows updated', 0 as 'number of multi-joined rows updated'")
@@ -177,6 +178,7 @@ class FakeSnowflakeCursor:
177
178
  .transform(transforms.indices_to_json_extract)
178
179
  .transform(transforms.json_extract_cast_as_varchar)
179
180
  .transform(transforms.json_extract_cased_as_varchar)
181
+ .transform(transforms.json_extract_precedence)
180
182
  .transform(transforms.flatten)
181
183
  .transform(transforms.regex_replace)
182
184
  .transform(transforms.regex_substr)
@@ -196,6 +198,10 @@ class FakeSnowflakeCursor:
196
198
  .transform(transforms.identifier)
197
199
  .transform(lambda e: transforms.show_schemas(e, self._conn.database))
198
200
  .transform(lambda e: transforms.show_objects_tables(e, self._conn.database))
201
+ # TODO collapse into a single show_keys function
202
+ .transform(lambda e: transforms.show_keys(e, self._conn.database, kind="PRIMARY"))
203
+ .transform(lambda e: transforms.show_keys(e, self._conn.database, kind="UNIQUE"))
204
+ .transform(lambda e: transforms.show_keys(e, self._conn.database, kind="FOREIGN"))
199
205
  .transform(transforms.show_users)
200
206
  .transform(transforms.create_user)
201
207
  )
@@ -230,12 +236,18 @@ class FakeSnowflakeCursor:
230
236
  raise snowflake.connector.errors.DatabaseError(msg=e.args[0], errno=250002, sqlstate="08003") from None
231
237
 
232
238
  affected_count = None
233
- if cmd == "USE DATABASE" and (ident := expression.find(exp.Identifier)) and isinstance(ident.this, str):
234
- self._conn.database = ident.this.upper()
239
+
240
+ if (maybe_ident := expression.find(exp.Identifier, bfs=False)) and isinstance(maybe_ident.this, str):
241
+ ident = maybe_ident.this if maybe_ident.quoted else maybe_ident.this.upper()
242
+ else:
243
+ ident = None
244
+
245
+ if cmd == "USE DATABASE" and ident:
246
+ self._conn.database = ident
235
247
  self._conn.database_set = True
236
248
 
237
- elif cmd == "USE SCHEMA" and (ident := expression.find(exp.Identifier)) and isinstance(ident.this, str):
238
- self._conn.schema = ident.this.upper()
249
+ elif cmd == "USE SCHEMA" and ident:
250
+ self._conn.schema = ident
239
251
  self._conn.schema_set = True
240
252
 
241
253
  elif create_db_name := transformed.args.get("create_db_name"):
@@ -243,24 +255,24 @@ class FakeSnowflakeCursor:
243
255
  self._duck_conn.execute(info_schema.creation_sql(create_db_name))
244
256
  result_sql = SQL_CREATED_DATABASE.substitute(name=create_db_name)
245
257
 
246
- elif cmd == "CREATE SCHEMA" and (ident := expression.find(exp.Identifier)) and isinstance(ident.this, str):
247
- name = ident.this if ident.quoted else ident.this.upper()
248
- result_sql = SQL_CREATED_SCHEMA.substitute(name=name)
258
+ elif cmd == "CREATE SCHEMA" and ident:
259
+ result_sql = SQL_CREATED_SCHEMA.substitute(name=ident)
260
+
261
+ elif cmd == "CREATE TABLE" and ident:
262
+ result_sql = SQL_CREATED_TABLE.substitute(name=ident)
249
263
 
250
- elif cmd == "CREATE TABLE" and (ident := expression.find(exp.Identifier)) and isinstance(ident.this, str):
251
- name = ident.this if ident.quoted else ident.this.upper()
252
- result_sql = SQL_CREATED_TABLE.substitute(name=name)
264
+ elif cmd == "CREATE VIEW" and ident:
265
+ result_sql = SQL_CREATED_VIEW.substitute(name=ident)
253
266
 
254
- elif cmd.startswith("DROP") and (ident := expression.find(exp.Identifier)) and isinstance(ident.this, str):
255
- name = ident.this if ident.quoted else ident.this.upper()
256
- result_sql = SQL_DROPPED.substitute(name=name)
267
+ elif cmd.startswith("DROP") and ident:
268
+ result_sql = SQL_DROPPED.substitute(name=ident)
257
269
 
258
270
  # if dropping the current database/schema then reset conn metadata
259
- if cmd == "DROP DATABASE" and name == self._conn.database:
271
+ if cmd == "DROP DATABASE" and ident == self._conn.database:
260
272
  self._conn.database = None
261
273
  self._conn.schema = None
262
274
 
263
- elif cmd == "DROP SCHEMA" and name == self._conn.schema:
275
+ elif cmd == "DROP SCHEMA" and ident == self._conn.schema:
264
276
  self._conn.schema = None
265
277
 
266
278
  elif cmd == "INSERT":
fakesnow/info_schema.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """Info schema extension tables/views used for storing snowflake metadata not captured by duckdb."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from string import Template
@@ -35,28 +36,45 @@ create table if not exists ${catalog}.information_schema._fs_columns_ext (
35
36
  SQL_CREATE_INFORMATION_SCHEMA_COLUMNS_VIEW = Template(
36
37
  """
37
38
  create view if not exists ${catalog}.information_schema._fs_columns_snowflake AS
38
- select table_catalog, table_schema, table_name, column_name, ordinal_position, column_default, is_nullable,
39
- case when starts_with(data_type, 'DECIMAL') or data_type='BIGINT' then 'NUMBER'
40
- when data_type='VARCHAR' then 'TEXT'
41
- when data_type='DOUBLE' then 'FLOAT'
42
- when data_type='BLOB' then 'BINARY'
43
- when data_type='TIMESTAMP' then 'TIMESTAMP_NTZ'
44
- when data_type='TIMESTAMP WITH TIME ZONE' then 'TIMESTAMP_TZ'
45
- when data_type='JSON' then 'VARIANT'
46
- else data_type end as data_type,
39
+ select
40
+ columns.table_catalog AS table_catalog,
41
+ columns.table_schema AS table_schema,
42
+ columns.table_name AS table_name,
43
+ columns.column_name AS column_name,
44
+ columns.ordinal_position AS ordinal_position,
45
+ columns.column_default AS column_default,
46
+ columns.is_nullable AS is_nullable,
47
+ case when starts_with(columns.data_type, 'DECIMAL') or columns.data_type='BIGINT' then 'NUMBER'
48
+ when columns.data_type='VARCHAR' then 'TEXT'
49
+ when columns.data_type='DOUBLE' then 'FLOAT'
50
+ when columns.data_type='BLOB' then 'BINARY'
51
+ when columns.data_type='TIMESTAMP' then 'TIMESTAMP_NTZ'
52
+ when columns.data_type='TIMESTAMP WITH TIME ZONE' then 'TIMESTAMP_TZ'
53
+ when columns.data_type='JSON' then 'VARIANT'
54
+ else columns.data_type end as data_type,
47
55
  ext_character_maximum_length as character_maximum_length, ext_character_octet_length as character_octet_length,
48
- case when data_type='BIGINT' then 38
49
- when data_type='DOUBLE' then NULL
50
- else numeric_precision end as numeric_precision,
51
- case when data_type='BIGINT' then 10
52
- when data_type='DOUBLE' then NULL
53
- else numeric_precision_radix end as numeric_precision_radix,
54
- case when data_type='DOUBLE' then NULL else numeric_scale end as numeric_scale,
55
- collation_name, is_identity, identity_generation, identity_cycle
56
- from ${catalog}.information_schema.columns
56
+ case when columns.data_type='BIGINT' then 38
57
+ when columns.data_type='DOUBLE' then NULL
58
+ else columns.numeric_precision end as numeric_precision,
59
+ case when columns.data_type='BIGINT' then 10
60
+ when columns.data_type='DOUBLE' then NULL
61
+ else columns.numeric_precision_radix end as numeric_precision_radix,
62
+ case when columns.data_type='DOUBLE' then NULL else columns.numeric_scale end as numeric_scale,
63
+ collation_name, is_identity, identity_generation, identity_cycle,
64
+ ddb_columns.comment as comment,
65
+ null as identity_start,
66
+ null as identity_increment,
67
+ from ${catalog}.information_schema.columns columns
57
68
  left join ${catalog}.information_schema._fs_columns_ext ext
58
- on ext_table_catalog = table_catalog AND ext_table_schema = table_schema
59
- AND ext_table_name = table_name AND ext_column_name = column_name
69
+ on ext_table_catalog = columns.table_catalog
70
+ AND ext_table_schema = columns.table_schema
71
+ AND ext_table_name = columns.table_name
72
+ AND ext_column_name = columns.column_name
73
+ LEFT JOIN duckdb_columns ddb_columns
74
+ ON ddb_columns.database_name = columns.table_catalog
75
+ AND ddb_columns.schema_name = columns.table_schema
76
+ AND ddb_columns.table_name = columns.table_name
77
+ AND ddb_columns.column_name = columns.column_name
60
78
  """
61
79
  )
62
80
 
fakesnow/transforms.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from pathlib import Path
4
4
  from string import Template
5
- from typing import cast
5
+ from typing import Literal, cast
6
6
 
7
7
  import sqlglot
8
8
  from sqlglot import exp
@@ -38,7 +38,8 @@ def create_database(expression: exp.Expression, db_path: Path | None = None) ->
38
38
  """
39
39
 
40
40
  if isinstance(expression, exp.Create) and str(expression.args.get("kind")).upper() == "DATABASE":
41
- assert (ident := expression.find(exp.Identifier)), f"No identifier in {expression.sql}"
41
+ ident = expression.find(exp.Identifier)
42
+ assert ident, f"No identifier in {expression.sql}"
42
43
  db_name = ident.this
43
44
  db_file = f"{db_path/db_name}.db" if db_path else ":memory:"
44
45
 
@@ -449,6 +450,16 @@ def json_extract_cast_as_varchar(expression: exp.Expression) -> exp.Expression:
449
450
  return expression
450
451
 
451
452
 
453
+ def json_extract_precedence(expression: exp.Expression) -> exp.Expression:
454
+ """Associate json extract operands to avoid duckdb operators of higher precedence transforming the expression.
455
+
456
+ See https://github.com/tekumara/fakesnow/issues/53
457
+ """
458
+ if isinstance(expression, exp.JSONExtract):
459
+ return exp.Paren(this=expression)
460
+ return expression
461
+
462
+
452
463
  def random(expression: exp.Expression) -> exp.Expression:
453
464
  """Convert random() and random(seed).
454
465
 
@@ -671,55 +682,61 @@ def set_schema(expression: exp.Expression, current_database: str | None) -> exp.
671
682
  return expression
672
683
 
673
684
 
674
- SQL_SHOW_OBJECTS = """
675
- select
676
- to_timestamp(0)::timestamptz as 'created_on',
677
- table_name as 'name',
678
- case when table_type='BASE TABLE' then 'TABLE' else table_type end as 'kind',
679
- table_catalog as 'database_name',
680
- table_schema as 'schema_name'
681
- from information_schema.tables
682
- """
683
-
684
-
685
685
  def show_objects_tables(expression: exp.Expression, current_database: str | None = None) -> exp.Expression:
686
686
  """Transform SHOW OBJECTS/TABLES to a query against the information_schema.tables table.
687
687
 
688
688
  See https://docs.snowflake.com/en/sql-reference/sql/show-objects
689
689
  https://docs.snowflake.com/en/sql-reference/sql/show-tables
690
690
  """
691
- if (
691
+ if not (
692
692
  isinstance(expression, exp.Show)
693
693
  and isinstance(expression.this, str)
694
- and expression.this.upper() in ["OBJECTS", "TABLES"]
694
+ and (show := expression.this.upper())
695
+ and show in {"OBJECTS", "TABLES"}
695
696
  ):
696
- scope_kind = expression.args.get("scope_kind")
697
- table = expression.find(exp.Table)
698
-
699
- if scope_kind == "DATABASE":
700
- catalog = (table and table.name) or current_database
701
- schema = None
702
- elif scope_kind == "SCHEMA" and table:
703
- catalog = table.db or current_database
704
- schema = table.name
705
- else:
706
- # all objects / tables
707
- catalog = None
708
- schema = None
709
-
710
- tables_only = "table_type = 'BASE TABLE' and " if expression.this.upper() == "TABLES" else ""
711
- exclude_fakesnow_tables = "not (table_schema == 'information_schema' and table_name like '_fs_%%')"
712
- # without a database will show everything in the "account"
713
- table_catalog = f" and table_catalog = '{catalog}'" if catalog else ""
714
- schema = f" and table_schema = '{schema}'" if schema else ""
715
- limit = limit.sql() if (limit := expression.args.get("limit")) and isinstance(limit, exp.Expression) else ""
716
-
717
- return sqlglot.parse_one(
718
- f"{SQL_SHOW_OBJECTS} where {tables_only}{exclude_fakesnow_tables}{table_catalog}{schema}{limit}",
719
- read="duckdb",
720
- )
697
+ return expression
721
698
 
722
- return expression
699
+ scope_kind = expression.args.get("scope_kind")
700
+ table = expression.find(exp.Table)
701
+
702
+ if scope_kind == "DATABASE":
703
+ catalog = (table and table.name) or current_database
704
+ schema = None
705
+ elif scope_kind == "SCHEMA" and table:
706
+ catalog = table.db or current_database
707
+ schema = table.name
708
+ else:
709
+ # all objects / tables
710
+ catalog = None
711
+ schema = None
712
+
713
+ tables_only = "table_type = 'BASE TABLE' and " if show == "TABLES" else ""
714
+ exclude_fakesnow_tables = "not (table_schema == 'information_schema' and table_name like '_fs_%%')"
715
+ # without a database will show everything in the "account"
716
+ table_catalog = f" and table_catalog = '{catalog}'" if catalog else ""
717
+ schema = f" and table_schema = '{schema}'" if schema else ""
718
+ limit = limit.sql() if (limit := expression.args.get("limit")) and isinstance(limit, exp.Expression) else ""
719
+
720
+ columns = [
721
+ "to_timestamp(0)::timestamptz as 'created_on'",
722
+ "table_name as 'name'",
723
+ "case when table_type='BASE TABLE' then 'TABLE' else table_type end as 'kind'",
724
+ "table_catalog as 'database_name'",
725
+ "table_schema as 'schema_name'",
726
+ ]
727
+
728
+ terse = expression.args["terse"]
729
+ if not terse:
730
+ columns.append('null as "comment"')
731
+
732
+ columns_str = ", ".join(columns)
733
+
734
+ query = (
735
+ f"SELECT {columns_str} from information_schema.tables "
736
+ f"where {tables_only}{exclude_fakesnow_tables}{table_catalog}{schema}{limit}"
737
+ )
738
+
739
+ return sqlglot.parse_one(query, read="duckdb")
723
740
 
724
741
 
725
742
  SQL_SHOW_SCHEMAS = """
@@ -987,3 +1004,86 @@ def create_user(expression: exp.Expression) -> exp.Expression:
987
1004
  return sqlglot.parse_one(f"INSERT INTO {USERS_TABLE_FQ_NAME} (name) VALUES ('{name}')", read="duckdb")
988
1005
 
989
1006
  return expression
1007
+
1008
+
1009
+ def show_keys(
1010
+ expression: exp.Expression,
1011
+ current_database: str | None = None,
1012
+ *,
1013
+ kind: Literal["PRIMARY", "UNIQUE", "FOREIGN"],
1014
+ ) -> exp.Expression:
1015
+ """Transform SHOW <kind> KEYS to a query against the duckdb_constraints meta-table.
1016
+
1017
+ https://docs.snowflake.com/en/sql-reference/sql/show-primary-keys
1018
+ """
1019
+ snowflake_kind = kind
1020
+ if kind == "FOREIGN":
1021
+ snowflake_kind = "IMPORTED"
1022
+
1023
+ if (
1024
+ isinstance(expression, exp.Show)
1025
+ and isinstance(expression.this, str)
1026
+ and expression.this.upper() == f"{snowflake_kind} KEYS"
1027
+ ):
1028
+ if kind == "FOREIGN":
1029
+ statement = f"""
1030
+ SELECT
1031
+ to_timestamp(0)::timestamptz as created_on,
1032
+
1033
+ '' as pk_database_name,
1034
+ '' as pk_schema_name,
1035
+ '' as pk_table_name,
1036
+ '' as pk_column_name,
1037
+ unnest(constraint_column_names) as pk_column_name,
1038
+
1039
+ database_name as fk_database_name,
1040
+ schema_name as fk_schema_name,
1041
+ table_name as fk_table_name,
1042
+ unnest(constraint_column_names) as fk_column_name,
1043
+ 1 as key_sequence,
1044
+ 'NO ACTION' as update_rule,
1045
+ 'NO ACTION' as delete_rule,
1046
+ LOWER(CONCAT(database_name, '_', schema_name, '_', table_name, '_pkey')) AS fk_name,
1047
+ LOWER(CONCAT(database_name, '_', schema_name, '_', table_name, '_pkey')) AS pk_name,
1048
+ 'NOT DEFERRABLE' as deferrability,
1049
+ 'false' as rely,
1050
+ null as "comment"
1051
+ FROM duckdb_constraints
1052
+ WHERE constraint_type = 'PRIMARY KEY'
1053
+ AND database_name = '{current_database}'
1054
+ AND table_name NOT LIKE '_fs_%'
1055
+ """
1056
+ else:
1057
+ statement = f"""
1058
+ SELECT
1059
+ to_timestamp(0)::timestamptz as created_on,
1060
+ database_name as database_name,
1061
+ schema_name as schema_name,
1062
+ table_name as table_name,
1063
+ unnest(constraint_column_names) as column_name,
1064
+ 1 as key_sequence,
1065
+ LOWER(CONCAT(database_name, '_', schema_name, '_', table_name, '_pkey')) AS constraint_name,
1066
+ 'false' as rely,
1067
+ null as "comment"
1068
+ FROM duckdb_constraints
1069
+ WHERE constraint_type = '{kind} KEY'
1070
+ AND database_name = '{current_database}'
1071
+ AND table_name NOT LIKE '_fs_%'
1072
+ """
1073
+
1074
+ scope_kind = expression.args.get("scope_kind")
1075
+ if scope_kind:
1076
+ table = expression.args["scope"]
1077
+
1078
+ if scope_kind == "SCHEMA":
1079
+ db = table and table.db
1080
+ schema = table and table.name
1081
+ if db:
1082
+ statement += f"AND database_name = '{db}' "
1083
+
1084
+ if schema:
1085
+ statement += f"AND schema_name = '{schema}' "
1086
+ else:
1087
+ raise NotImplementedError(f"SHOW PRIMARY KEYS with {scope_kind} not yet supported")
1088
+ return sqlglot.parse_one(statement)
1089
+ return expression
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fakesnow
3
- Version: 0.9.4
3
+ Version: 0.9.6
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
@@ -213,20 +213,20 @@ License-File: LICENSE
213
213
  Requires-Dist: duckdb ~=0.10.0
214
214
  Requires-Dist: pyarrow
215
215
  Requires-Dist: snowflake-connector-python
216
- Requires-Dist: sqlglot ~=21.1.0
216
+ Requires-Dist: sqlglot ~=21.2.0
217
217
  Provides-Extra: dev
218
- Requires-Dist: black ~=23.9 ; extra == 'dev'
219
218
  Requires-Dist: build ~=1.0 ; extra == 'dev'
219
+ 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
- Requires-Dist: pytest ~=7.4 ; extra == 'dev'
223
- Requires-Dist: ruff ~=0.1.6 ; extra == 'dev'
224
- Requires-Dist: twine ~=4.0 ; extra == 'dev'
222
+ Requires-Dist: pytest ~=8.0 ; extra == 'dev'
223
+ Requires-Dist: ruff ~=0.3.2 ; extra == 'dev'
224
+ Requires-Dist: twine ~=5.0 ; extra == 'dev'
225
+ Requires-Dist: snowflake-sqlalchemy ~=1.5.0 ; extra == 'dev'
225
226
  Provides-Extra: notebook
226
227
  Requires-Dist: duckdb-engine ; extra == 'notebook'
227
228
  Requires-Dist: ipykernel ; extra == 'notebook'
228
229
  Requires-Dist: jupysql ; extra == 'notebook'
229
- Requires-Dist: snowflake-sqlalchemy ; extra == 'notebook'
230
230
 
231
231
  # fakesnow ❄️
232
232
 
@@ -234,6 +234,8 @@ Requires-Dist: snowflake-sqlalchemy ; extra == 'notebook'
234
234
  [![release](https://github.com/tekumara/fakesnow/actions/workflows/release.yml/badge.svg)](https://github.com/tekumara/fakesnow/actions/workflows/release.yml)
235
235
  [![PyPI](https://img.shields.io/pypi/v/fakesnow?color=violet)](https://pypi.org/project/fakesnow/)
236
236
 
237
+ [![ci](../../actions/workflows/ci.yml/badge.svg)](../../actions/workflows/ci.yml)
238
+
237
239
  Fake [Snowflake Connector for Python](https://docs.snowflake.com/en/user-guide/python-connector). Run and mock Snowflake DB locally.
238
240
 
239
241
  ## Install
@@ -356,7 +358,7 @@ For more detail see [tests/test_fakes.py](tests/test_fakes.py)
356
358
  ## Caveats
357
359
 
358
360
  - The order of rows is non deterministic and may not match Snowflake unless ORDER BY is fully specified.
359
- - VARCHAR field sizes are not enforced. Unlike Snowflake which errors with "User character length limit (xxx) exceeded by string" when an inserted string exceeds the column limit.
361
+ - 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
362
 
361
363
  ## Contributing
362
364
 
@@ -0,0 +1,18 @@
1
+ fakesnow/__init__.py,sha256=KWTeAxTcWXClN4bNo4kWHbC0ukOum7A4vtuL9zC1pT0,3472
2
+ fakesnow/__main__.py,sha256=GDrGyNTvBFuqn_UfDjKs7b3LPtU6gDv1KwosVDrukIM,76
3
+ fakesnow/checks.py,sha256=-QMvdcrRbhN60rnzxLBJ0IkUBWyLR8gGGKKmCS0w9mA,2383
4
+ fakesnow/cli.py,sha256=9qfI-Ssr6mo8UmIlXkUAOz2z2YPBgDsrEVaZv9FjGFs,2201
5
+ fakesnow/expr.py,sha256=CAxuYIUkwI339DQIBzvFF0F-m1tcVGKEPA5rDTzmH9A,892
6
+ fakesnow/fakes.py,sha256=5Fq_Qk-Iqxxzl-1XkcMyGDw2NY5hzE_50e5xii-jxhA,28463
7
+ fakesnow/fixtures.py,sha256=G-NkVeruSQAJ7fvSS2fR2oysUn0Yra1pohHlOvacKEk,455
8
+ fakesnow/global_database.py,sha256=WTVIP1VhNvdCeX7TQncX1TRpGQU5rBf5Pbxim40zeSU,1399
9
+ fakesnow/info_schema.py,sha256=CdIcGXHEQ_kmEAzdQKvA-PX41LA6wlK-4p1J45qgKYA,6266
10
+ fakesnow/macros.py,sha256=pX1YJDnQOkFJSHYUjQ6ErEkYIKvFI6Ncz_au0vv1csA,265
11
+ fakesnow/py.typed,sha256=B-DLSjYBi7pkKjwxCSdpVj2J02wgfJr-E7B1wOUyxYU,80
12
+ fakesnow/transforms.py,sha256=4cGfNbcd-X1l0UEGFudjoRejTjxSwWo-E0NXGpdVlaE,40109
13
+ fakesnow-0.9.6.dist-info/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
14
+ fakesnow-0.9.6.dist-info/METADATA,sha256=PBc3zlOgUpHFpxAJoTHnZaKcgZz8J6LqfVnP_yMytRw,17802
15
+ fakesnow-0.9.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
16
+ fakesnow-0.9.6.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
17
+ fakesnow-0.9.6.dist-info/top_level.txt,sha256=500evXI1IFX9so82cizGIEMHAb_dJNPaZvd2H9dcKTA,24
18
+ fakesnow-0.9.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,18 +0,0 @@
1
- fakesnow/__init__.py,sha256=UGfEpHKJWFEZfx_myvXuMyxMiHrFjfJmKnJcRQMyxL8,3443
2
- fakesnow/__main__.py,sha256=GDrGyNTvBFuqn_UfDjKs7b3LPtU6gDv1KwosVDrukIM,76
3
- fakesnow/checks.py,sha256=-QMvdcrRbhN60rnzxLBJ0IkUBWyLR8gGGKKmCS0w9mA,2383
4
- fakesnow/cli.py,sha256=9qfI-Ssr6mo8UmIlXkUAOz2z2YPBgDsrEVaZv9FjGFs,2201
5
- fakesnow/expr.py,sha256=CAxuYIUkwI339DQIBzvFF0F-m1tcVGKEPA5rDTzmH9A,892
6
- fakesnow/fakes.py,sha256=gNw5tRu00pcC8m3CdLfv06wrHxBm_In8kJQ-IGNXp-Y,28197
7
- fakesnow/fixtures.py,sha256=G-NkVeruSQAJ7fvSS2fR2oysUn0Yra1pohHlOvacKEk,455
8
- fakesnow/global_database.py,sha256=WTVIP1VhNvdCeX7TQncX1TRpGQU5rBf5Pbxim40zeSU,1399
9
- fakesnow/info_schema.py,sha256=5Rbq5HWb1YG-QY4Fj5zUC8KWRNt42aHw2J7tfHtbCug,5544
10
- fakesnow/macros.py,sha256=pX1YJDnQOkFJSHYUjQ6ErEkYIKvFI6Ncz_au0vv1csA,265
11
- fakesnow/py.typed,sha256=B-DLSjYBi7pkKjwxCSdpVj2J02wgfJr-E7B1wOUyxYU,80
12
- fakesnow/transforms.py,sha256=z9tZDOtvQDAoYmQDvDegUOwxgBFvjnSfKCo7kTc-ryA,36300
13
- fakesnow-0.9.4.dist-info/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
14
- fakesnow-0.9.4.dist-info/METADATA,sha256=4-uOp2P5nWelvwky5v7htSJPcLlZaJ0DtURryGxAdp4,17724
15
- fakesnow-0.9.4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
16
- fakesnow-0.9.4.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
17
- fakesnow-0.9.4.dist-info/top_level.txt,sha256=500evXI1IFX9so82cizGIEMHAb_dJNPaZvd2H9dcKTA,24
18
- fakesnow-0.9.4.dist-info/RECORD,,