fakesnow 0.4.1__py3-none-any.whl → 0.5.1__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/fakes.py CHANGED
@@ -46,6 +46,7 @@ class FakeSnowflakeCursor:
46
46
  self._use_dict_result = use_dict_result
47
47
  self._last_sql = None
48
48
  self._last_params = None
49
+ self._sqlstate = None
49
50
 
50
51
  def __enter__(self) -> Self:
51
52
  return self
@@ -76,7 +77,7 @@ class FakeSnowflakeCursor:
76
77
  # use a cursor to avoid destroying an unfetched result on the main connection
77
78
  with self._duck_conn.cursor() as cur:
78
79
  assert self._conn.database, "Not implemented when database is None"
79
- assert self._conn.schema, "Not implemented when database is None"
80
+ assert self._conn.schema, "Not implemented when schema is None"
80
81
 
81
82
  # match database and schema used on the main connection
82
83
  cur.execute(f"SET SCHEMA = '{self._conn.database}.{self._conn.schema}'")
@@ -91,6 +92,20 @@ class FakeSnowflakeCursor:
91
92
  params: Sequence[Any] | dict[Any, Any] | None = None,
92
93
  *args: Any,
93
94
  **kwargs: Any,
95
+ ) -> FakeSnowflakeCursor:
96
+ try:
97
+ self._sqlstate = None
98
+ return self._execute(command, params, *args, **kwargs)
99
+ except snowflake.connector.errors.ProgrammingError as e:
100
+ self._sqlstate = e.sqlstate
101
+ raise e
102
+
103
+ def _execute(
104
+ self,
105
+ command: str | exp.Expression,
106
+ params: Sequence[Any] | dict[Any, Any] | None = None,
107
+ *args: Any,
108
+ **kwargs: Any,
94
109
  ) -> FakeSnowflakeCursor:
95
110
  self._arrow_table = None
96
111
 
@@ -108,13 +123,13 @@ class FakeSnowflakeCursor:
108
123
  msg=f"Cannot perform {cmd}. This session does not have a current database. Call 'USE DATABASE', or use a qualified name.", # noqa: E501
109
124
  errno=90105,
110
125
  sqlstate="22000",
111
- ) from None
126
+ )
112
127
  elif no_schema and not self._conn.schema_set:
113
128
  raise snowflake.connector.errors.ProgrammingError(
114
129
  msg=f"Cannot perform {cmd}. This session does not have a current schema. Call 'USE SCHEMA', or use a qualified name.", # noqa: E501
115
130
  errno=90106,
116
131
  sqlstate="22000",
117
- ) from None
132
+ )
118
133
 
119
134
  transformed = (
120
135
  expression.transform(transforms.upper_case_unquoted_identifiers)
@@ -247,13 +262,21 @@ class FakeSnowflakeCursor:
247
262
  # TODO: return number of rows updated/inserted (using returning)
248
263
  return None
249
264
 
265
+ @property
266
+ def sfqid(self) -> str | None:
267
+ return "fakesnow"
268
+
269
+ @property
270
+ def sqlstate(self) -> str | None:
271
+ return self._sqlstate
272
+
250
273
  @staticmethod
251
274
  def _describe_as_result_metadata(describe_results: list) -> list[ResultMetadata]:
252
275
  # fmt: off
253
276
  def as_result_metadata(column_name: str, column_type: str, _: str) -> ResultMetadata:
254
277
  # see https://docs.snowflake.com/en/user-guide/python-connector-api.html#type-codes
255
278
  # and https://arrow.apache.org/docs/python/api/datatypes.html#type-checking
256
- if column_type == "BIGINT":
279
+ if column_type in {"BIGINT", "INTEGER"}:
257
280
  return ResultMetadata(
258
281
  name=column_name, type_code=0, display_size=None, internal_size=None, precision=38, scale=0, is_nullable=True # noqa: E501
259
282
  )
@@ -288,6 +311,14 @@ class FakeSnowflakeCursor:
288
311
  return ResultMetadata(
289
312
  name=column_name, type_code=8, display_size=None, internal_size=None, precision=0, scale=9, is_nullable=True # noqa: E501
290
313
  )
314
+ elif column_type == "BLOB":
315
+ return ResultMetadata(
316
+ name=column_name, type_code=11, display_size=None, internal_size=8388608, precision=None, scale=None, is_nullable=True # noqa: E501
317
+ )
318
+ elif column_type == "TIME":
319
+ return ResultMetadata(
320
+ name=column_name, type_code=12, display_size=None, internal_size=None, precision=0, scale=9, is_nullable=True # noqa: E501
321
+ )
291
322
  else:
292
323
  # TODO handle more types
293
324
  raise NotImplementedError(f"for column type {column_type}")
fakesnow/info_schema.py CHANGED
@@ -37,11 +37,18 @@ create view ${catalog}.information_schema.columns_snowflake AS
37
37
  select table_catalog, table_schema, table_name, column_name, ordinal_position, column_default, is_nullable,
38
38
  case when starts_with(data_type, 'DECIMAL') or data_type='BIGINT' then 'NUMBER'
39
39
  when data_type='VARCHAR' then 'TEXT'
40
+ when data_type='DOUBLE' then 'FLOAT'
41
+ when data_type='BLOB' then 'BINARY'
42
+ when data_type='TIMESTAMP' then 'TIMESTAMP_NTZ'
40
43
  else data_type end as data_type,
41
44
  ext_character_maximum_length as character_maximum_length, ext_character_octet_length as character_octet_length,
42
- case when data_type='BIGINT' then 38 else numeric_precision end as numeric_precision,
43
- case when data_type='BIGINT' then 10 else numeric_precision_radix end as numeric_precision_radix,
44
- numeric_scale,
45
+ case when data_type='BIGINT' then 38
46
+ when data_type='DOUBLE' then NULL
47
+ else numeric_precision end as numeric_precision,
48
+ case when data_type='BIGINT' then 10
49
+ when data_type='DOUBLE' then NULL
50
+ else numeric_precision_radix end as numeric_precision_radix,
51
+ case when data_type='DOUBLE' then NULL else numeric_scale end as numeric_scale,
45
52
  collation_name, is_identity, identity_generation, identity_cycle
46
53
  from ${catalog}.information_schema.columns
47
54
  left join ${catalog}.information_schema.columns_ext ext
fakesnow/transforms.py CHANGED
@@ -181,10 +181,7 @@ def float_to_double(expression: exp.Expression) -> exp.Expression:
181
181
  """
182
182
 
183
183
  if isinstance(expression, exp.DataType) and expression.this == exp.DataType.Type.FLOAT:
184
- # TODO don't copy!
185
- new = expression.copy()
186
- new.args["this"] = exp.DataType.Type.DOUBLE
187
- return new
184
+ expression.args["this"] = exp.DataType.Type.DOUBLE
188
185
 
189
186
  return expression
190
187
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fakesnow
3
- Version: 0.4.1
3
+ Version: 0.5.1
4
4
  Summary: Fake Snowflake Connector for Python. Run Snowflake DB locally.
5
5
  License: MIT License
6
6
 
@@ -124,12 +124,13 @@ def _fakesnow_session() -> Iterator[None]:
124
124
 
125
125
  ## Implementation coverage
126
126
 
127
- - [x] multiple databases
128
- - [x] cursors
127
+ - [x] cursors and standard SQL
129
128
  - [x] [get_result_batches()](https://docs.snowflake.com/en/user-guide/python-connector-api#get_result_batches)
130
- - [x] [write_pandas(..)](https://docs.snowflake.com/en/user-guide/python-connector-api#write_pandas)
131
- - [x] table comments
129
+ - [x] information schema
130
+ - [x] multiple databases
132
131
  - [x] [qmark binding](https://docs.snowflake.com/en/user-guide/python-connector-example#binding-data)
132
+ - [x] table comments
133
+ - [x] [write_pandas(..)](https://docs.snowflake.com/en/user-guide/python-connector-api#write_pandas)
133
134
  - [ ] [access control](https://docs.snowflake.com/en/user-guide/security-access-control-overview)
134
135
  - [ ] standalone/out of process api/support for faking non-python connectors
135
136
  - [ ] [stored procedures](https://docs.snowflake.com/en/sql-reference/stored-procedures)
@@ -137,8 +138,9 @@ def _fakesnow_session() -> Iterator[None]:
137
138
  Partial support
138
139
 
139
140
  - [x] date functions
140
- - [x] tags
141
+ - [x] regex functions
141
142
  - [x] semi-structured data
143
+ - [x] tags
142
144
 
143
145
  For more detail see [tests/test_fakes.py](tests/test_fakes.py)
144
146
 
@@ -0,0 +1,13 @@
1
+ fakesnow/__init__.py,sha256=ogZl2Z61FIiU2fg8WiM1FhXYLpG-Phvg855nmuMhdqQ,2992
2
+ fakesnow/checks.py,sha256=1qVLR0ZB3z3UPij3Hm8hqlkcNLH2QJnwe8OqkoFCwv8,2356
3
+ fakesnow/expr.py,sha256=CAxuYIUkwI339DQIBzvFF0F-m1tcVGKEPA5rDTzmH9A,892
4
+ fakesnow/fakes.py,sha256=v6t0sLy9KsiiUW-KyRggamt7K7ADEw8uSXdQt6HmQN4,20760
5
+ fakesnow/fixtures.py,sha256=LANb4LuiUjKbTZRHmgnAi50xC1rs1xF8SHLoBikB88c,509
6
+ fakesnow/info_schema.py,sha256=0eJgDJ0sbEUVNcfGBb5hdCR2SiKJYmO0MA-ZnnsUhbo,3781
7
+ fakesnow/py.typed,sha256=B-DLSjYBi7pkKjwxCSdpVj2J02wgfJr-E7B1wOUyxYU,80
8
+ fakesnow/transforms.py,sha256=PTK3RA1SEiCT9urw97tLyhzXZuWZx5hCUWcvPO2DIwI,22305
9
+ fakesnow-0.5.1.dist-info/LICENSE,sha256=BL6v_VTnU7xdsocviIQJMFr3stX_-uRfTyByo3gRu4M,1071
10
+ fakesnow-0.5.1.dist-info/METADATA,sha256=H2Lo5Okt1MPsbpBW2CfeDYX9Yti-d8sTUOWFNAaHW8k,5225
11
+ fakesnow-0.5.1.dist-info/WHEEL,sha256=AtBG6SXL3KF_v0NxLf0ehyVOh0cold-JbJYXNGorC6Q,92
12
+ fakesnow-0.5.1.dist-info/top_level.txt,sha256=x8S-sMmvfgNm2_1w0zlIF5YlDs2hR7eNQdVA6TgmPZE,14
13
+ fakesnow-0.5.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.40.0)
2
+ Generator: bdist_wheel (0.41.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,13 +0,0 @@
1
- fakesnow/__init__.py,sha256=ogZl2Z61FIiU2fg8WiM1FhXYLpG-Phvg855nmuMhdqQ,2992
2
- fakesnow/checks.py,sha256=1qVLR0ZB3z3UPij3Hm8hqlkcNLH2QJnwe8OqkoFCwv8,2356
3
- fakesnow/expr.py,sha256=CAxuYIUkwI339DQIBzvFF0F-m1tcVGKEPA5rDTzmH9A,892
4
- fakesnow/fakes.py,sha256=6PYHwykRDXaHM1sET-A-ZGTrDrQ0DPyjsxWgpPW-mP0,19626
5
- fakesnow/fixtures.py,sha256=LANb4LuiUjKbTZRHmgnAi50xC1rs1xF8SHLoBikB88c,509
6
- fakesnow/info_schema.py,sha256=4GnYuAWsX9qfQKQyTd-GkI24DHAxHCmGCst6ohcQAXY,3495
7
- fakesnow/py.typed,sha256=B-DLSjYBi7pkKjwxCSdpVj2J02wgfJr-E7B1wOUyxYU,80
8
- fakesnow/transforms.py,sha256=VqkxxtDu8RbetcDMBm4nMCGyzuXwpU8-0WqXkmKSEhU,22376
9
- fakesnow-0.4.1.dist-info/LICENSE,sha256=BL6v_VTnU7xdsocviIQJMFr3stX_-uRfTyByo3gRu4M,1071
10
- fakesnow-0.4.1.dist-info/METADATA,sha256=5rRxOoTmT7yoJ75KJf211cXrey4LWrQ1wWvoyxCzhNo,5161
11
- fakesnow-0.4.1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
12
- fakesnow-0.4.1.dist-info/top_level.txt,sha256=x8S-sMmvfgNm2_1w0zlIF5YlDs2hR7eNQdVA6TgmPZE,14
13
- fakesnow-0.4.1.dist-info/RECORD,,