fakesnow 0.9.33__py3-none-any.whl → 0.9.35__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/converter.py ADDED
@@ -0,0 +1,60 @@
1
+ from __future__ import annotations
2
+
3
+ import binascii
4
+ import datetime
5
+ from datetime import date, time, timezone
6
+
7
+ # convert server bindings from strings into python types
8
+
9
+
10
+ def from_binding(binding: dict[str, str]) -> int | bytes | bool | date | time | datetime.datetime | str:
11
+ typ = binding["type"]
12
+ value = binding["value"]
13
+ if typ == "FIXED":
14
+ return int(value)
15
+ elif typ == "BINARY":
16
+ return from_binary(value)
17
+ # TODO: not strictly needed
18
+ elif typ == "BOOLEAN":
19
+ return value.lower() == "true"
20
+ elif typ == "DATE":
21
+ return from_date(value)
22
+ elif typ == "TIME":
23
+ return from_time(value)
24
+ elif typ == "TIMESTAMP_NTZ":
25
+ return from_datetime(value)
26
+ else:
27
+ # For other types, return str
28
+ return value
29
+
30
+
31
+ def from_binary(s: str) -> bytes:
32
+ return binascii.unhexlify(s)
33
+
34
+
35
+ def from_boolean(s: str) -> bool:
36
+ return s.lower() == "true"
37
+
38
+
39
+ def from_date(s: str) -> date:
40
+ milliseconds = int(s)
41
+ seconds = milliseconds / 1000
42
+ return datetime.datetime.fromtimestamp(seconds, timezone.utc).date()
43
+
44
+
45
+ def from_time(s: str) -> time:
46
+ nanoseconds = int(s)
47
+ microseconds = nanoseconds / 1000
48
+ return (
49
+ datetime.datetime.fromtimestamp(microseconds / 1_000_000, timezone.utc)
50
+ .replace(microsecond=int(microseconds % 1_000_000))
51
+ .time()
52
+ )
53
+
54
+
55
+ def from_datetime(s: str) -> datetime.datetime:
56
+ nanoseconds = int(s)
57
+ microseconds = nanoseconds / 1000
58
+ return datetime.datetime.fromtimestamp(microseconds / 1_000_000, timezone.utc).replace(
59
+ microsecond=int(microseconds % 1_000_000)
60
+ )
fakesnow/cursor.py CHANGED
@@ -139,7 +139,12 @@ class FakeSnowflakeCursor:
139
139
  print(f"{command};{params=}" if params else f"{command};", file=sys.stderr)
140
140
 
141
141
  command = self._inline_variables(command)
142
- command, params = self._rewrite_with_params(command, params)
142
+ if kwargs.get("binding_params"):
143
+ # params have come via the server
144
+ params = kwargs["binding_params"]
145
+ else:
146
+ command, params = self._rewrite_with_params(command, params)
147
+
143
148
  if self._conn.nop_regexes and any(re.match(p, command, re.IGNORECASE) for p in self._conn.nop_regexes):
144
149
  transformed = transforms.SUCCESS_NOP
145
150
  self._execute(transformed, params)
@@ -161,6 +166,9 @@ class FakeSnowflakeCursor:
161
166
  # strip highlight for better readability, TODO: show pointer to start of error
162
167
  msg = str(e).replace("\x1b[4m", "").replace("\x1b[0m", "")
163
168
  raise snowflake.connector.errors.ProgrammingError(msg=msg, errno=1003, sqlstate="42000") from None
169
+ except NotImplementedError as e:
170
+ msg = f"{e} not implemented. Please raise an issue via https://github.com/tekumara/fakesnow/issues/new"
171
+ raise snowflake.connector.errors.ProgrammingError(msg=msg, errno=9999, sqlstate="99999") from e
164
172
 
165
173
  def check_db_and_schema(self, expression: exp.Expression) -> None:
166
174
  no_database, no_schema = checks.is_unqualified_table_expression(expression)
@@ -233,7 +241,7 @@ class FakeSnowflakeCursor:
233
241
  .transform(transforms.show_procedures)
234
242
  .transform(transforms.show_warehouses)
235
243
  .transform(lambda e: transforms.show_schemas(e, self._conn.database))
236
- .transform(lambda e: transforms.show_objects_tables(e, self._conn.database))
244
+ .transform(lambda e: transforms.show_tables_etc(e, self._conn.database))
237
245
  .transform(lambda e: transforms.show_columns(e, self._conn.database))
238
246
  # TODO collapse into a single show_keys function
239
247
  .transform(lambda e: transforms.show_keys(e, self._conn.database, kind="PRIMARY"))
@@ -384,7 +392,7 @@ class FakeSnowflakeCursor:
384
392
  self._sfqid = str(uuid.uuid4())
385
393
 
386
394
  self._last_sql = result_sql or sql
387
- self._last_params = params
395
+ self._last_params = None if result_sql else params
388
396
 
389
397
  def _log_sql(self, sql: str, params: Sequence[Any] | dict[Any, Any] | None = None) -> None:
390
398
  if (fs_debug := os.environ.get("FAKESNOW_DEBUG")) and fs_debug != "snowflake":
@@ -398,7 +406,7 @@ class FakeSnowflakeCursor:
398
406
  ) -> FakeSnowflakeCursor:
399
407
  if isinstance(seqparams, dict):
400
408
  # see https://docs.snowflake.com/en/developer-guide/python-connector/python-connector-api
401
- raise NotImplementedError("dict params not supported yet")
409
+ raise NotImplementedError("executemany dict params")
402
410
 
403
411
  # TODO: support insert optimisations
404
412
  # the snowflake connector will optimise inserts into a single query
fakesnow/info_schema.py CHANGED
@@ -34,8 +34,8 @@ create table if not exists _fs_global._fs_information_schema._fs_columns_ext (
34
34
  """
35
35
 
36
36
  # replicates the output structure of https://docs.snowflake.com/en/sql-reference/sql/show-users
37
- SQL_CREATE_GLOBAL_INFORMATION_SCHEMA_USERS_TABLE_EXT = """
38
- create table if not exists _fs_global._fs_information_schema._fs_users_ext (
37
+ SQL_CREATE_GLOBAL_INFORMATION_SCHEMA_USERS_TABLE = """
38
+ create table if not exists _fs_global._fs_information_schema._fs_users (
39
39
  name varchar,
40
40
  created_on TIMESTAMPTZ,
41
41
  login_name varchar,
@@ -196,13 +196,13 @@ def per_db_creation_sql(catalog: str) -> str:
196
196
  """
197
197
 
198
198
 
199
- def fs_global_creation_sql(catalog: str) -> str:
199
+ def fs_global_creation_sql() -> str:
200
200
  return f"""
201
201
  {SQL_CREATE_GLOBAL_FS_INFORMATION_SCHEMA};
202
202
  {SQL_CREATE_GLOBAL_INFORMATION_SCHEMA_TABLES_EXT};
203
203
  {SQL_CREATE_GLOBAL_INFORMATION_SCHEMA_COLUMNS_EXT};
204
204
  {SQL_CREATE_GLOBAL_INFORMATION_SCHEMA_COLUMNS_VIEW};
205
- {SQL_CREATE_GLOBAL_INFORMATION_SCHEMA_USERS_TABLE_EXT};
205
+ {SQL_CREATE_GLOBAL_INFORMATION_SCHEMA_USERS_TABLE};
206
206
  """
207
207
 
208
208
 
fakesnow/instance.py CHANGED
@@ -7,6 +7,7 @@ import duckdb
7
7
 
8
8
  import fakesnow.fakes as fakes
9
9
  from fakesnow import info_schema
10
+ from fakesnow.transforms import show
10
11
 
11
12
  GLOBAL_DATABASE_NAME = "_fs_global"
12
13
 
@@ -28,8 +29,9 @@ class FakeSnow:
28
29
 
29
30
  # create a "global" database for storing objects which span databases.
30
31
  self.duck_conn.execute(f"ATTACH IF NOT EXISTS ':memory:' AS {GLOBAL_DATABASE_NAME}")
31
- # create the info schema extensions
32
- self.duck_conn.execute(info_schema.fs_global_creation_sql(GLOBAL_DATABASE_NAME))
32
+ # create the info schema extensions and show views
33
+ self.duck_conn.execute(info_schema.fs_global_creation_sql())
34
+ self.duck_conn.execute(show.fs_global_creation_sql())
33
35
 
34
36
  # use UTC instead of local time zone for consistent testing
35
37
  self.duck_conn.execute("SET GLOBAL TimeZone = 'UTC'")
fakesnow/server.py CHANGED
@@ -16,6 +16,7 @@ from starlette.responses import JSONResponse
16
16
  from starlette.routing import Route
17
17
 
18
18
  from fakesnow.arrow import to_ipc, to_sf
19
+ from fakesnow.converter import from_binding
19
20
  from fakesnow.fakes import FakeSnowflakeConnection
20
21
  from fakesnow.instance import FakeSnow
21
22
  from fakesnow.rowtype import describe_as_rowtype
@@ -77,9 +78,16 @@ async def query_request(request: Request) -> JSONResponse:
77
78
 
78
79
  sql_text = body_json["sqlText"]
79
80
 
81
+ if bindings := body_json.get("bindings"):
82
+ # Convert parameters like {'1': {'type': 'FIXED', 'value': '10'}, ...} to tuple (10, ...)
83
+ params = tuple(from_binding(bindings[str(pos)]) for pos in range(1, len(bindings) + 1))
84
+ logger.debug(f"Bindings: {params}")
85
+ else:
86
+ params = None
87
+
80
88
  try:
81
89
  # only a single sql statement is sent at a time by the python snowflake connector
82
- cur = await run_in_threadpool(conn.cursor().execute, sql_text)
90
+ cur = await run_in_threadpool(conn.cursor().execute, sql_text, binding_params=params)
83
91
  rowtype = describe_as_rowtype(cur._describe_last_sql()) # noqa: SLF001
84
92
 
85
93
  except snowflake.connector.errors.ProgrammingError as e:
@@ -113,6 +121,9 @@ async def query_request(request: Request) -> JSONResponse:
113
121
  return JSONResponse(
114
122
  {
115
123
  "data": {
124
+ "parameters": [
125
+ {"name": "TIMEZONE", "value": "Etc/UTC"},
126
+ ],
116
127
  "rowtype": rowtype,
117
128
  "rowsetBase64": rowset_b64,
118
129
  "total": cur._rowcount, # noqa: SLF001
@@ -13,9 +13,9 @@ from fakesnow.transforms.show import (
13
13
  show_databases as show_databases,
14
14
  show_functions as show_functions,
15
15
  show_keys as show_keys,
16
- show_objects_tables as show_objects_tables,
17
16
  show_procedures as show_procedures,
18
17
  show_schemas as show_schemas,
18
+ show_tables_etc as show_tables_etc,
19
19
  show_users as show_users,
20
20
  show_warehouses as show_warehouses,
21
21
  )
@@ -837,7 +837,7 @@ def regex_replace(expression: exp.Expression) -> exp.Expression:
837
837
  if len(expression.args) > 3:
838
838
  # see https://docs.snowflake.com/en/sql-reference/functions/regexp_replace
839
839
  raise NotImplementedError(
840
- "REGEXP_REPLACE with additional parameters (eg: <position>, <occurrence>, <parameters>) not supported"
840
+ "REGEXP_REPLACE with additional parameters (eg: <position>, <occurrence>, <parameters>)"
841
841
  )
842
842
 
843
843
  # pattern: snowflake requires escaping backslashes in single-quoted string constants, but duckdb doesn't
@@ -1316,9 +1316,9 @@ def create_user(expression: exp.Expression) -> exp.Expression:
1316
1316
  if sub_exp.upper().startswith("USER"):
1317
1317
  _, name, *ignored = sub_exp.split(" ")
1318
1318
  if ignored:
1319
- raise NotImplementedError(f"`CREATE USER` with {ignored} not yet supported")
1319
+ raise NotImplementedError(f"`CREATE USER` with {ignored}")
1320
1320
  return sqlglot.parse_one(
1321
- f"INSERT INTO _fs_global._fs_information_schema._fs_users_ext (name) VALUES ('{name}')", read="duckdb"
1321
+ f"INSERT INTO _fs_global._fs_information_schema._fs_users (name) VALUES ('{name}')", read="duckdb"
1322
1322
  )
1323
1323
 
1324
1324
  return expression
@@ -6,6 +6,14 @@ import sqlglot
6
6
  from sqlglot import exp
7
7
 
8
8
 
9
+ def fs_global_creation_sql() -> str:
10
+ return f"""
11
+ {SQL_CREATE_VIEW_SHOW_OBJECTS};
12
+ {SQL_CREATE_VIEW_SHOW_TABLES};
13
+ {SQL_CREATE_VIEW_SHOW_VIEWS};
14
+ """
15
+
16
+
9
17
  def show_columns(
10
18
  expression: exp.Expression, current_database: str | None = None, current_schema: str | None = None
11
19
  ) -> exp.Expression:
@@ -283,22 +291,99 @@ def show_keys(
283
291
 
284
292
  statement += f"AND table_name = '{table.name}' "
285
293
  else:
286
- raise NotImplementedError(f"SHOW PRIMARY KEYS with {scope_kind} not yet supported")
294
+ raise NotImplementedError(f"SHOW PRIMARY KEYS with {scope_kind}")
287
295
  return sqlglot.parse_one(statement)
288
296
  return expression
289
297
 
290
298
 
291
- def show_objects_tables(expression: exp.Expression, current_database: str | None = None) -> exp.Expression:
292
- """Transform SHOW OBJECTS/TABLES to a query against the information_schema.tables table.
299
+ # see https://docs.snowflake.com/en/sql-reference/sql/show-objects
300
+ SQL_CREATE_VIEW_SHOW_OBJECTS = """
301
+ create view if not exists _fs_global._fs_information_schema._fs_show_objects as
302
+ select
303
+ to_timestamp(0)::timestamptz as created_on,
304
+ table_name as name,
305
+ case when table_type='BASE TABLE' then 'TABLE' else table_type end as 'kind',
306
+ table_catalog as database_name,
307
+ table_schema as schema_name,
308
+ '' as comment,
309
+ '' as cluster_by,
310
+ -- TODO: implement rows and bytes as rows * 1024
311
+ 0 as rows,
312
+ 0 as bytes,
313
+ 'SYSADMIN' as owner,
314
+ 1 as retention_time,
315
+ 'ROLE' as owner_role_type,
316
+ null as budget,
317
+ 'N' as is_hybrid,
318
+ 'N' as is_dynamic
319
+ from information_schema.tables
320
+ where not (table_schema == '_fs_information_schema')
321
+ """
293
322
 
294
- See https://docs.snowflake.com/en/sql-reference/sql/show-objects
295
- https://docs.snowflake.com/en/sql-reference/sql/show-tables
296
- """
323
+ # see https://docs.snowflake.com/en/sql-reference/sql/show-tables
324
+ SQL_CREATE_VIEW_SHOW_TABLES = """
325
+ create view if not exists _fs_global._fs_information_schema._fs_show_tables as
326
+ select
327
+ to_timestamp(0)::timestamptz as created_on,
328
+ table_name as name,
329
+ 'TABLE' as kind,
330
+ table_catalog as database_name,
331
+ table_schema as schema_name,
332
+ '' as comment,
333
+ '' as cluster_by,
334
+ -- TODO: implement rows and bytes as rows * 1024
335
+ 0 as rows,
336
+ 0 as bytes,
337
+ 'SYSADMIN' as owner,
338
+ 1 as retention_time,
339
+ 'OFF' as automatic_clustering,
340
+ 'OFF' as change_tracking,
341
+ 'OFF' as search_optimization,
342
+ null as search_optimization_progress,
343
+ null as search_optimization_bytes,
344
+ 'N' as is_external,
345
+ 'N' as enable_schema_evolution,
346
+ 'ROLE' as owner_role_type,
347
+ 'N' as is_event,
348
+ null as budget,
349
+ 'N' as is_hybrid,
350
+ 'N' as is_iceberg,
351
+ 'N' as is_dynamic,
352
+ 'N' as is_immutable
353
+ from information_schema.tables
354
+ where not (table_schema == '_fs_information_schema')
355
+ and table_type = 'BASE TABLE'
356
+ """
357
+
358
+ # see https://docs.snowflake.com/en/sql-reference/sql/show-views
359
+ SQL_CREATE_VIEW_SHOW_VIEWS = """
360
+ create view if not exists _fs_global._fs_information_schema._fs_show_views as
361
+ select
362
+ to_timestamp(0)::timestamptz as created_on,
363
+ table_name as name,
364
+ '' as reserved,
365
+ table_catalog as database_name,
366
+ table_schema as schema_name,
367
+ 'SYSADMIN' as owner,
368
+ '' as comment,
369
+ view_definition as text,
370
+ false as is_secure,
371
+ false as is_materialized,
372
+ 'ROLE' as owner_role_type,
373
+ 'OFF' as change_tracking
374
+ from information_schema.views
375
+ where not table_catalog in ('system')
376
+ and not table_schema in ('main', '_fs_information_schema')
377
+ """
378
+
379
+
380
+ def show_tables_etc(expression: exp.Expression, current_database: str | None = None) -> exp.Expression:
381
+ """Transform SHOW OBJECTS/TABLES/VIEWS to a query against the _fs_information_schema views."""
297
382
  if not (
298
383
  isinstance(expression, exp.Show)
299
384
  and isinstance(expression.this, str)
300
385
  and (show := expression.this.upper())
301
- and show in {"OBJECTS", "TABLES"}
386
+ and show in {"OBJECTS", "TABLES", "VIEWS"}
302
387
  ):
303
388
  return expression
304
389
 
@@ -316,76 +401,28 @@ def show_objects_tables(expression: exp.Expression, current_database: str | None
316
401
  catalog = None
317
402
  schema = None
318
403
 
319
- columns = [
320
- "to_timestamp(0)::timestamptz as 'created_on'",
321
- "table_name as 'name'",
322
- "case when table_type='BASE TABLE' then 'TABLE' else table_type end as 'kind'",
323
- "table_catalog as 'database_name'",
324
- "table_schema as 'schema_name'",
325
- ]
326
- if not expression.args["terse"]:
327
- if show == "OBJECTS":
328
- columns.extend(
329
- [
330
- "'' as 'comment'",
331
- "'' as 'cluster_by'",
332
- # TODO: implement rows and bytes as rows * 1024
333
- "0 as 'rows'",
334
- "0 as 'bytes'",
335
- "'SYSADMIN' as 'owner'",
336
- "1 as 'retention_time'",
337
- "'ROLE' as 'owner_role_type'",
338
- "null as 'budget'",
339
- "'N' as 'is_hybrid'",
340
- "'N' as 'is_dynamic'",
341
- ]
342
- )
343
- else:
344
- # show == "TABLES"
345
- columns.extend(
346
- [
347
- "'' as 'comment'",
348
- "'' as 'cluster_by'",
349
- # TODO: implement rows and bytes as rows * 1024
350
- "0 as 'rows'",
351
- "0 as 'bytes'",
352
- "'SYSADMIN' as 'owner'",
353
- "1 as 'retention_time'",
354
- "'OFF' as 'automatic_clustering'",
355
- "'OFF' as 'change_tracking'",
356
- "'OFF' as 'search_optimization'",
357
- "null as 'search_optimization_progress'",
358
- "null as 'search_optimization_bytes'",
359
- "'N' as 'is_external'",
360
- "'N' as 'enable_schema_evolution'",
361
- "'ROLE' as 'owner_role_type'",
362
- "'N' as 'is_event'",
363
- "null as 'budget'",
364
- "'N' as 'is_hybrid'",
365
- "'N' as 'is_iceberg'",
366
- "'N' as 'is_dynamic'",
367
- "'N' as 'is_immutable'",
368
- ]
369
- )
370
-
404
+ if expression.args["terse"] and show == "VIEWS":
405
+ columns = ["created_on, name, 'VIEW' as kind, database_name, schema_name"]
406
+ elif expression.args["terse"]:
407
+ columns = ["created_on, name, kind, database_name, schema_name"]
408
+ else:
409
+ columns = ["*"]
371
410
  columns_clause = ", ".join(columns)
372
411
 
373
- where = ["not (table_schema == '_fs_information_schema')"] # exclude fakesnow's internal schemas
374
- if show == "TABLES":
375
- where.append("table_type = 'BASE TABLE'")
412
+ where = ["1=1"]
376
413
  if catalog:
377
- where.append(f"table_catalog = '{catalog}'")
414
+ where.append(f"database_name = '{catalog}'")
378
415
  if schema:
379
- where.append(f"table_schema = '{schema}'")
416
+ where.append(f"schema_name = '{schema}'")
380
417
  if (like := expression.args.get("like")) and isinstance(like, exp.Expression):
381
- where.append(f"table_name ilike {like.sql()}")
418
+ where.append(f"name ilike {like.sql()}")
382
419
  where_clause = " AND ".join(where)
383
420
 
384
421
  limit = limit.sql() if (limit := expression.args.get("limit")) and isinstance(limit, exp.Expression) else ""
385
422
 
386
423
  query = f"""
387
424
  SELECT {columns_clause}
388
- from information_schema.tables
425
+ from _fs_global._fs_information_schema._fs_show_{show.lower()}
389
426
  where {where_clause}
390
427
  {limit}
391
428
  """
@@ -471,6 +508,6 @@ def show_users(expression: exp.Expression) -> exp.Expression:
471
508
  https://docs.snowflake.com/en/sql-reference/sql/show-users
472
509
  """
473
510
  if isinstance(expression, exp.Show) and isinstance(expression.this, str) and expression.this.upper() == "USERS":
474
- return sqlglot.parse_one("SELECT * FROM _fs_global._fs_information_schema._fs_users_ext", read="duckdb")
511
+ return sqlglot.parse_one("SELECT * FROM _fs_global._fs_information_schema._fs_users", read="duckdb")
475
512
 
476
513
  return expression
fakesnow/variables.py CHANGED
@@ -45,7 +45,7 @@ class Variables:
45
45
  self._set(name, value)
46
46
  else:
47
47
  # Haven't been able to produce this in tests yet due to UNSET being parsed as an Alias expression.
48
- raise NotImplementedError("UNSET not supported yet")
48
+ raise NotImplementedError("UNSET")
49
49
  elif self._is_unset_expression(expr): # Unfortunately UNSET varname; is parsed as an Alias expression :(
50
50
  alias = expr.args.get("alias")
51
51
  assert alias, "UNSET without value in alias attribute is unexpected."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fakesnow
3
- Version: 0.9.33
3
+ Version: 0.9.35
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
@@ -4,25 +4,26 @@ fakesnow/arrow.py,sha256=XjTpFyLrD9jULWOtPgpr0RyNMmO6a5yi82y6ivi2CCI,4884
4
4
  fakesnow/checks.py,sha256=be-xo0oMoAUVhlMDCu1_Rkoh_L8p_p8qo9P6reJSHIQ,2874
5
5
  fakesnow/cli.py,sha256=9qfI-Ssr6mo8UmIlXkUAOz2z2YPBgDsrEVaZv9FjGFs,2201
6
6
  fakesnow/conn.py,sha256=2WClMmUgfQkQA2hFQjfMP3R-85TbTbZh_8Y1tCdcerA,6053
7
- fakesnow/cursor.py,sha256=Nvr8TQmmTFs6i0sJwfgCocrEF9td0D0SdDG41quIudI,21621
7
+ fakesnow/converter.py,sha256=xoBFnfBbGWQyUQAVr6zi-RyglU8A7A3GSlwLPkH1dzI,1621
8
+ fakesnow/cursor.py,sha256=e-nY-w25xmLs1jdhIbO6mwzBHVIUKYIkzR37Wnf3Cfc,22068
8
9
  fakesnow/expr.py,sha256=CAxuYIUkwI339DQIBzvFF0F-m1tcVGKEPA5rDTzmH9A,892
9
10
  fakesnow/fakes.py,sha256=JQTiUkkwPeQrJ8FDWhPFPK6pGwd_aR2oiOrNzCWznlM,187
10
11
  fakesnow/fixtures.py,sha256=G-NkVeruSQAJ7fvSS2fR2oysUn0Yra1pohHlOvacKEk,455
11
- fakesnow/info_schema.py,sha256=xDhGy07fpc8bcy_VTfh54UzwNIaB4ZhGmjgJeoiZ0hQ,8744
12
- fakesnow/instance.py,sha256=VsFbhVfy6EAJdEKykgavJwkMtrig01NehorptT51Jh8,2020
12
+ fakesnow/info_schema.py,sha256=AYmTIHxk5Y6xdMTgttgBL1V0VO8qiM2T1-gKwkLmWDs,8720
13
+ fakesnow/instance.py,sha256=OKoYXwaI6kL9HQpnHx44yzpON_xNfuIT_F4oJNF_XXQ,2114
13
14
  fakesnow/macros.py,sha256=pX1YJDnQOkFJSHYUjQ6ErEkYIKvFI6Ncz_au0vv1csA,265
14
15
  fakesnow/pandas_tools.py,sha256=wI203UQHC8JvDzxE_VjE1NeV4rThek2P-u52oTg2foo,3481
15
16
  fakesnow/py.typed,sha256=B-DLSjYBi7pkKjwxCSdpVj2J02wgfJr-E7B1wOUyxYU,80
16
17
  fakesnow/rowtype.py,sha256=QUp8EaXD5LT0Xv8BXk5ze4WseEn52xoJ6R05pJjs5mM,2729
17
- fakesnow/server.py,sha256=oLnWJgcxwhPw4sNebJF3B9uxk28A-a-AI8Pyl_lz2_E,5986
18
- fakesnow/variables.py,sha256=WXyPnkeNwD08gy52yF66CVe2twiYC50tztNfgXV4q1k,3032
19
- fakesnow/transforms/__init__.py,sha256=xFrpw28DaHvMt6LGaRMsPqTo8PWogg10JgEu3oa6jdA,49515
18
+ fakesnow/server.py,sha256=6EMdNMxL0DgfMNXfFBqRFYmRThbuEVFFpa_1sCW-rZ4,6519
19
+ fakesnow/variables.py,sha256=C3y_9u7LuVtARkpcim3ihgVWg6KKdz1hSVeW4YI7oL4,3014
20
+ fakesnow/transforms/__init__.py,sha256=eJ_XH9pKO4Mxb7MKVgJuo6Wea-LYahF1dc_py5lPHAY,49471
20
21
  fakesnow/transforms/merge.py,sha256=Pg7_rwbAT_vr1U4ocBofUSyqaK8_e3qdIz_2SDm2S3s,8320
21
- fakesnow/transforms/show.py,sha256=2qfK3Fi0RLylqTnkwSVgv5JIorXYb1y0fnf5oErRZ2o,16839
22
- fakesnow-0.9.33.dist-info/licenses/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
22
+ fakesnow/transforms/show.py,sha256=0NjuLQjodrukfUw8mcxcAmtBkV_6r02mA3nuE3ad3rE,17458
23
+ fakesnow-0.9.35.dist-info/licenses/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
23
24
  tools/decode.py,sha256=kC5kUvLQxdCkMRsnH6BqCajlKxKeN77w6rwCKsY6gqU,1781
24
- fakesnow-0.9.33.dist-info/METADATA,sha256=xOQPPYwFTgDETx_lx1bO2nBpD7wbqWwN1rn2U5MJHFw,18128
25
- fakesnow-0.9.33.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
26
- fakesnow-0.9.33.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
27
- fakesnow-0.9.33.dist-info/top_level.txt,sha256=Yos7YveA3f03xVYuURqnBsfMV2DePXfu_yGcsj3pPzI,30
28
- fakesnow-0.9.33.dist-info/RECORD,,
25
+ fakesnow-0.9.35.dist-info/METADATA,sha256=D2aDpQUAIuSHEf6W5f1m84IG3BBDEvvMN5fU_FiWl3c,18128
26
+ fakesnow-0.9.35.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
27
+ fakesnow-0.9.35.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
28
+ fakesnow-0.9.35.dist-info/top_level.txt,sha256=Yos7YveA3f03xVYuURqnBsfMV2DePXfu_yGcsj3pPzI,30
29
+ fakesnow-0.9.35.dist-info/RECORD,,