fakesnow 0.9.33__py3-none-any.whl → 0.9.34__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 +60 -0
- fakesnow/cursor.py +7 -2
- fakesnow/server.py +9 -1
- {fakesnow-0.9.33.dist-info → fakesnow-0.9.34.dist-info}/METADATA +1 -1
- {fakesnow-0.9.33.dist-info → fakesnow-0.9.34.dist-info}/RECORD +9 -8
- {fakesnow-0.9.33.dist-info → fakesnow-0.9.34.dist-info}/WHEEL +0 -0
- {fakesnow-0.9.33.dist-info → fakesnow-0.9.34.dist-info}/entry_points.txt +0 -0
- {fakesnow-0.9.33.dist-info → fakesnow-0.9.34.dist-info}/licenses/LICENSE +0 -0
- {fakesnow-0.9.33.dist-info → fakesnow-0.9.34.dist-info}/top_level.txt +0 -0
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 bindings provided as strings to the server 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
|
-
|
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)
|
@@ -384,7 +389,7 @@ class FakeSnowflakeCursor:
|
|
384
389
|
self._sfqid = str(uuid.uuid4())
|
385
390
|
|
386
391
|
self._last_sql = result_sql or sql
|
387
|
-
self._last_params = params
|
392
|
+
self._last_params = None if result_sql else params
|
388
393
|
|
389
394
|
def _log_sql(self, sql: str, params: Sequence[Any] | dict[Any, Any] | None = None) -> None:
|
390
395
|
if (fs_debug := os.environ.get("FAKESNOW_DEBUG")) and fs_debug != "snowflake":
|
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
|
+
params = None
|
82
|
+
|
83
|
+
if bindings := body_json.get("bindings"):
|
84
|
+
# Convert parameters like {'1': {'type': 'FIXED', 'value': '1'}, ...} to tuple (1, ...)
|
85
|
+
params = tuple(from_binding(bindings[str(pos)]) for pos in range(1, len(bindings) + 1))
|
86
|
+
logger.debug(f"Bindings: {params}")
|
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:
|
@@ -4,7 +4,8 @@ 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/
|
7
|
+
fakesnow/converter.py,sha256=7YlASaMomzchMZoorTH3KtVmgBakaHrF5fAl5VP747I,1635
|
8
|
+
fakesnow/cursor.py,sha256=mK4nC1iucON1MohicTugJqUOfRsx5c8ToUJgnCfUSbs,21813
|
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
|
@@ -14,15 +15,15 @@ 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=
|
18
|
+
fakesnow/server.py,sha256=4DgZUTd-G_usjSqy6NdUqd2fWUw2a-wHSSeJt3cdneA,6375
|
18
19
|
fakesnow/variables.py,sha256=WXyPnkeNwD08gy52yF66CVe2twiYC50tztNfgXV4q1k,3032
|
19
20
|
fakesnow/transforms/__init__.py,sha256=xFrpw28DaHvMt6LGaRMsPqTo8PWogg10JgEu3oa6jdA,49515
|
20
21
|
fakesnow/transforms/merge.py,sha256=Pg7_rwbAT_vr1U4ocBofUSyqaK8_e3qdIz_2SDm2S3s,8320
|
21
22
|
fakesnow/transforms/show.py,sha256=2qfK3Fi0RLylqTnkwSVgv5JIorXYb1y0fnf5oErRZ2o,16839
|
22
|
-
fakesnow-0.9.
|
23
|
+
fakesnow-0.9.34.dist-info/licenses/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
|
23
24
|
tools/decode.py,sha256=kC5kUvLQxdCkMRsnH6BqCajlKxKeN77w6rwCKsY6gqU,1781
|
24
|
-
fakesnow-0.9.
|
25
|
-
fakesnow-0.9.
|
26
|
-
fakesnow-0.9.
|
27
|
-
fakesnow-0.9.
|
28
|
-
fakesnow-0.9.
|
25
|
+
fakesnow-0.9.34.dist-info/METADATA,sha256=Hqkb8CT1-QTNzQqRMVhEHWGwx3gJORv9YHy7wGSoBgQ,18128
|
26
|
+
fakesnow-0.9.34.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
27
|
+
fakesnow-0.9.34.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
|
28
|
+
fakesnow-0.9.34.dist-info/top_level.txt,sha256=Yos7YveA3f03xVYuURqnBsfMV2DePXfu_yGcsj3pPzI,30
|
29
|
+
fakesnow-0.9.34.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|