fakesnow 0.9.35__py3-none-any.whl → 0.9.37__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fakesnow
3
- Version: 0.9.35
3
+ Version: 0.9.37
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
@@ -204,7 +204,8 @@ License: Apache License
204
204
  See the License for the specific language governing permissions and
205
205
  limitations under the License.
206
206
 
207
- Project-URL: homepage, https://github.com/tekumara/fakesnow
207
+ Project-URL: Source, https://github.com/tekumara/fakesnow
208
+ Project-URL: Changelog, https://github.com/tekumara/fakesnow/blob/main/CHANGELOG.md
208
209
  Keywords: snowflake,snowflakedb,fake,local,mock,testing
209
210
  Classifier: License :: OSI Approved :: MIT License
210
211
  Requires-Python: >=3.9
@@ -213,23 +214,7 @@ License-File: LICENSE
213
214
  Requires-Dist: duckdb~=1.2.0
214
215
  Requires-Dist: pyarrow
215
216
  Requires-Dist: snowflake-connector-python
216
- Requires-Dist: sqlglot~=26.12.1
217
- Provides-Extra: dev
218
- Requires-Dist: build~=1.0; extra == "dev"
219
- Requires-Dist: dirty-equals; extra == "dev"
220
- Requires-Dist: pandas-stubs; extra == "dev"
221
- Requires-Dist: snowflake-connector-python[pandas,secure-local-storage]; extra == "dev"
222
- Requires-Dist: pre-commit~=4.0; extra == "dev"
223
- Requires-Dist: pyarrow-stubs==17.19; extra == "dev"
224
- Requires-Dist: pytest~=8.0; extra == "dev"
225
- Requires-Dist: pytest-asyncio; extra == "dev"
226
- Requires-Dist: ruff~=0.11.0; extra == "dev"
227
- Requires-Dist: twine~=6.0; extra == "dev"
228
- Requires-Dist: snowflake-sqlalchemy~=1.7.0; extra == "dev"
229
- Provides-Extra: notebook
230
- Requires-Dist: duckdb-engine; extra == "notebook"
231
- Requires-Dist: ipykernel; extra == "notebook"
232
- Requires-Dist: jupysql; extra == "notebook"
217
+ Requires-Dist: sqlglot~=26.16.2
233
218
  Provides-Extra: server
234
219
  Requires-Dist: starlette; extra == "server"
235
220
  Requires-Dist: uvicorn; extra == "server"
@@ -242,7 +227,7 @@ Dynamic: license-file
242
227
  [![PyPI](https://img.shields.io/pypi/v/fakesnow?color=violet)](https://pypi.org/project/fakesnow/)
243
228
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/fakesnow?color=violet)](https://pypi.org/project/fakesnow/)
244
229
 
245
- Fake [Snowflake Connector for Python](https://docs.snowflake.com/en/user-guide/python-connector). Run and mock Snowflake DB locally.
230
+ Run, mock and test fake Snowflake databases locally.
246
231
 
247
232
  ## Install
248
233
 
@@ -250,9 +235,21 @@ Fake [Snowflake Connector for Python](https://docs.snowflake.com/en/user-guide/p
250
235
  pip install fakesnow
251
236
  ```
252
237
 
238
+ Or to install with the server:
239
+
240
+ ```
241
+ pip install fakesnow[server]
242
+ ```
243
+
253
244
  ## Usage
254
245
 
255
- Run script.py with fakesnow:
246
+ fakesnow offers two main approaches for faking Snowflake: [in-process patching](#in-process-patching) of the Snowflake Connector for Python or a [standalone HTTP server](#run-fakesnow-as-a-server).
247
+
248
+ Patching only applies to the current Python process. If a subprocess is spawned it won't be patched. For subprocesses, or for non-Python clients, use the server instead.
249
+
250
+ ### In-process patching
251
+
252
+ To run script.py with patching:
256
253
 
257
254
  ```shell
258
255
  fakesnow script.py
@@ -266,9 +263,9 @@ fakesnow -m pytest
266
263
 
267
264
  `fakesnow` executes `fakesnow.patch` before running the script or module.
268
265
 
269
- ### fakesnow.patch
266
+ #### Use fakesnow.patch in your code
270
267
 
271
- To use fakesnow within your code:
268
+ Alternatively, use fakesnow.patch in your code:
272
269
 
273
270
  ```python
274
271
  import fakesnow
@@ -280,12 +277,16 @@ with fakesnow.patch():
280
277
  print(conn.cursor().execute("SELECT 'Hello fake world!'").fetchone())
281
278
  ```
282
279
 
283
- The following imports are automatically patched:
280
+ #### What gets patched
281
+
282
+ The following standard imports are automatically patched:
284
283
 
285
284
  - `import snowflake.connector.connect`
286
285
  - `import snowflake.connector.pandas_tools.write_pandas`
287
286
 
288
- To patch modules that use the `from ... import` syntax, manually specify them, eg: if _mymodule.py_ has the import:
287
+ #### Handling "from ... import" Statements
288
+
289
+ To patch modules that use the `from ... import` syntax, you need to manually specify them, eg: if _mymodule.py_ contains:
289
290
 
290
291
  ```python
291
292
  from snowflake.connector.pandas_tools import write_pandas
@@ -298,33 +299,83 @@ with fakesnow.patch("mymodule.write_pandas"):
298
299
  ...
299
300
  ```
300
301
 
301
- By default databases are in-memory. To persist databases between processes, specify a databases path:
302
+ #### Database Persistence
303
+
304
+ By default, databases are in-memory and will be lost when the process ends. To persist databases between processes, specify a databases path:
302
305
 
303
306
  ```python
304
307
  with fakesnow.patch(db_path="databases/"):
305
308
  ...
306
309
  ```
307
310
 
311
+ ### Run fakesnow as a server
312
+
313
+ For scenarios where patching won't work (like subprocesses or non-Python clients), you can run fakesnow as an HTTP server:
314
+
315
+ ```python
316
+ import fakesnow
317
+ import snowflake.connector
318
+
319
+ # Start the fakesnow server in a context manager
320
+ # This yields connection kwargs (host, port, etc.)
321
+ with fakesnow.server() as conn_kwargs:
322
+ # Connect to the fakesnow server using the yielded kwargs
323
+ with snowflake.connector.connect(**conn_kwargs) as conn:
324
+ print(conn.cursor().execute("SELECT 'Hello fake server!'").fetchone())
325
+
326
+ # The server is automatically stopped when exiting the context manager
327
+ ```
328
+
329
+ This starts an HTTP server in its own thread listening for requests on localhost on an available random port.
330
+ The server accepts any username/password combination.
331
+
332
+ #### Server Configuration Options
333
+
334
+ By default, the server uses a single in-memory database for its lifetime. To configure database persistence or isolation:
335
+
336
+ ```python
337
+ # Databases will be saved to the "databases/" directory
338
+ with fakesnow.server(session_parameters={"FAKESNOW_DB_PATH": "databases/"}):
339
+ ...
340
+
341
+ # Each connection gets its own isolated in-memory database
342
+ with fakesnow.server(session_parameters={"FAKESNOW_DB_PATH": ":isolated:"}):
343
+ ...
344
+ ```
345
+
346
+ To specify a port for the server:
347
+
348
+ ```python
349
+ with fakesnow.server(port=12345) as conn_kwargs:
350
+ ...
351
+ ```
352
+
308
353
  ### pytest fixtures
309
354
 
310
- pytest [fixtures](fakesnow/fixtures.py) are provided for testing. Example _conftest.py_:
355
+ fakesnow provides [fixtures](fakesnow/fixtures.py) for easier test integration. Add them in _conftest.py_:
356
+
357
+ ```python
358
+ pytest_plugins = "fakesnow.fixtures"
359
+ ```
360
+
361
+ To autouse the fixture you can wrap it like this in _conftest.py_:
311
362
 
312
363
  ```python
313
364
  from typing import Iterator
314
365
 
315
- import fakesnow.fixtures
316
366
  import pytest
317
367
 
318
- pytest_plugins = fakesnow.fixtures.__name__
368
+ pytest_plugins = "fakesnow.fixtures"
319
369
 
320
370
  @pytest.fixture(scope="session", autouse=True)
321
371
  def setup(_fakesnow_session: None) -> Iterator[None]:
322
372
  # the standard imports are now patched
323
- ...
373
+ # Add any additional setup here
324
374
  yield
375
+ # Add any teardown here
325
376
  ```
326
377
 
327
- Or with `from ... import` patch targets:
378
+ For code that uses `from ... import` statements:
328
379
 
329
380
  ```python
330
381
  from typing import Iterator
@@ -332,40 +383,72 @@ from typing import Iterator
332
383
  import fakesnow
333
384
  import pytest
334
385
 
386
+ pytest_plugins = "fakesnow.fixtures"
387
+
335
388
  @pytest.fixture(scope="session", autouse=True)
336
389
  def _fakesnow_session() -> Iterator[None]:
337
390
  with fakesnow.patch("mymodule.write_pandas"):
338
391
  yield
339
392
  ```
340
393
 
394
+ #### server fixture
395
+
396
+ To start a fakesnow server instance, enable the plugin in _conftest.py_:
397
+
398
+ ```python
399
+ pytest_plugins = "fakesnow.fixtures"
400
+ ```
401
+
402
+ And then use the `fakesnow_server` session fixture like this:
403
+
404
+ ```python
405
+ import snowflake.connector
406
+
407
+ def test_with_server(fakesnow_server: dict):
408
+ # fakesnow_server contains connection kwargs (host, port, etc.)
409
+ with snowflake.connector.connect(**fakesnow_server) as conn:
410
+ conn.cursor().execute("SELECT 1")
411
+ assert conn.cursor().fetchone() == (1,)
412
+ ```
413
+
341
414
  ## Implementation coverage
342
415
 
343
- - [x] cursors and standard SQL
344
- - [x] [get_result_batches()](https://docs.snowflake.com/en/user-guide/python-connector-api#get_result_batches)
345
- - [x] information schema
346
- - [x] multiple databases
347
- - [x] [parameter binding](https://docs.snowflake.com/en/user-guide/python-connector-example#binding-data)
348
- - [x] table comments
349
- - [x] [write_pandas(..)](https://docs.snowflake.com/en/user-guide/python-connector-api#write_pandas)
350
- - [ ] [access control](https://docs.snowflake.com/en/user-guide/security-access-control-overview)
351
- - [ ] standalone/out of process api/support for faking non-python connectors
352
- - [ ] [stored procedures](https://docs.snowflake.com/en/sql-reference/stored-procedures)
416
+ Fully supported:
417
+
418
+ - Standard SQL operations and cursors
419
+ - Information schema queries
420
+ - Multiple databases
421
+ - [Parameter binding](https://docs.snowflake.com/en/user-guide/python-connector-example#binding-data) in queries
422
+ - Table comments
423
+ - Pandas integration including [write_pandas(..)](https://docs.snowflake.com/en/user-guide/python-connector-api#write_pandas) (not available via the server yet)
424
+ - Result batch retrieval via [get_result_batches()](https://docs.snowflake.com/en/user-guide/python-connector-api#get_result_batches)
425
+ - HTTP server for non-Python connectors
426
+
427
+ Partially supported:
353
428
 
354
- Partial support
429
+ - Date functions
430
+ - Regular expression functions
431
+ - Semi-structured data operations
432
+ - Tags
433
+ - User management
434
+ - `COPY INTO` from S3 sources, see [COPY INTO](#copy-into)
355
435
 
356
- - [x] date functions
357
- - [x] regex functions
358
- - [x] semi-structured data
359
- - [x] tags
360
- - [x] user management (See [tests/test_users.py](tests/test_users.py))
436
+ Not yet implemented:
361
437
 
362
- For more detail see [tests/test_fakes.py](tests/test_fakes.py)
438
+ - [Access control](https://docs.snowflake.com/en/user-guide/security-access-control-overview)
439
+ - [Stored procedures](https://docs.snowflake.com/en/sql-reference/stored-procedures)
440
+
441
+ For more detail see the [test suite](tests/).
363
442
 
364
443
  ## Caveats
365
444
 
366
- - The order of rows is non deterministic and may not match Snowflake unless ORDER BY is fully specified.
367
- - 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.
445
+ - Row ordering is non-deterministic and may differ from Snowflake unless you fully specify the ORDER BY clause.
446
+ - fakesnow supports a more liberal SQL dialect than actual Snowflake. This means some queries that work with fakesnow might not work with a real Snowflake instance.
447
+
448
+ ## COPY INTO
449
+
450
+ `COPY INTO` can be used from S3 sources. By default the standard AWS credential chain will be used. If you are getting an HTTP 403 or need to provide alternative S3 credentials you can use the duckdb [CREATE SECRET](https://duckdb.org/docs/stable/extensions/httpfs/s3api) statement. For an example of creating a secret to use a moto S3 endpoint see `s3_client` in [conftest.py](tests/conftest.py#L80)
368
451
 
369
452
  ## Contributing
370
453
 
371
- See [CONTRIBUTING.md](CONTRIBUTING.md) to get started and develop in this repo.
454
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for instructions on getting started with development and contributing to this project.
@@ -0,0 +1,32 @@
1
+ fakesnow/__init__.py,sha256=71Rk_3s_4eTDCi7-bbo-xT71WN0E0MAPf5qjsguIeJU,5117
2
+ fakesnow/__main__.py,sha256=GDrGyNTvBFuqn_UfDjKs7b3LPtU6gDv1KwosVDrukIM,76
3
+ fakesnow/arrow.py,sha256=XjTpFyLrD9jULWOtPgpr0RyNMmO6a5yi82y6ivi2CCI,4884
4
+ fakesnow/checks.py,sha256=be-xo0oMoAUVhlMDCu1_Rkoh_L8p_p8qo9P6reJSHIQ,2874
5
+ fakesnow/cli.py,sha256=9qfI-Ssr6mo8UmIlXkUAOz2z2YPBgDsrEVaZv9FjGFs,2201
6
+ fakesnow/conn.py,sha256=diCwcjaCBrlCn9PyjbScfIQTNQjqiPTkQanUTqcvblE,6009
7
+ fakesnow/converter.py,sha256=wPOfsFXIUJNJSx5oFNAxh13udxmAVIIHsLK8BiGkXGA,1635
8
+ fakesnow/copy_into.py,sha256=JT4SpynozlcdmWwzlQwwncPiuHCE5UUv-XGX_CI9s90,7235
9
+ fakesnow/cursor.py,sha256=so8OET_ZLlvRyxanKORfGU8gSiIa71FKILsS45lh0cE,22287
10
+ fakesnow/expr.py,sha256=CAxuYIUkwI339DQIBzvFF0F-m1tcVGKEPA5rDTzmH9A,892
11
+ fakesnow/fakes.py,sha256=JQTiUkkwPeQrJ8FDWhPFPK6pGwd_aR2oiOrNzCWznlM,187
12
+ fakesnow/fixtures.py,sha256=2rj0MTZlaZc4PNWhaqC5IiiLa7E9G0QZT3g45YawsL0,633
13
+ fakesnow/info_schema.py,sha256=AYmTIHxk5Y6xdMTgttgBL1V0VO8qiM2T1-gKwkLmWDs,8720
14
+ fakesnow/instance.py,sha256=OKoYXwaI6kL9HQpnHx44yzpON_xNfuIT_F4oJNF_XXQ,2114
15
+ fakesnow/logger.py,sha256=U6EjUENQuTrDeNYqER2hxazoySmXzLmZJ-t-SDZgjkg,363
16
+ fakesnow/macros.py,sha256=bQfZR5ptO4Gk-8fFRK2iksqYWkJUT8e-rPp-000qzu0,999
17
+ fakesnow/pandas_tools.py,sha256=wI203UQHC8JvDzxE_VjE1NeV4rThek2P-u52oTg2foo,3481
18
+ fakesnow/py.typed,sha256=B-DLSjYBi7pkKjwxCSdpVj2J02wgfJr-E7B1wOUyxYU,80
19
+ fakesnow/rowtype.py,sha256=QUp8EaXD5LT0Xv8BXk5ze4WseEn52xoJ6R05pJjs5mM,2729
20
+ fakesnow/server.py,sha256=RHf7ffKYi5xBH9fh8wZr3tEPmnzFWuvUbziCC8UwTh4,6652
21
+ fakesnow/variables.py,sha256=C3y_9u7LuVtARkpcim3ihgVWg6KKdz1hSVeW4YI7oL4,3014
22
+ fakesnow/transforms/__init__.py,sha256=jHbn7T6fSxhiu3KVn_Xupi5JwgY9SbjcfGU-0WpdELU,2769
23
+ fakesnow/transforms/merge.py,sha256=Pg7_rwbAT_vr1U4ocBofUSyqaK8_e3qdIz_2SDm2S3s,8320
24
+ fakesnow/transforms/show.py,sha256=0NjuLQjodrukfUw8mcxcAmtBkV_6r02mA3nuE3ad3rE,17458
25
+ fakesnow/transforms/transforms.py,sha256=kjkQGTSkZ5lOJ-G13WQL4uB4yTzoIcsa3qcgBAgPH0c,47985
26
+ fakesnow-0.9.37.dist-info/licenses/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
27
+ tools/decode.py,sha256=kC5kUvLQxdCkMRsnH6BqCajlKxKeN77w6rwCKsY6gqU,1781
28
+ fakesnow-0.9.37.dist-info/METADATA,sha256=6tfEtq0EvcWJEor8o4E-XgwkpO-gd5rh2o6EZ7BqRcc,20680
29
+ fakesnow-0.9.37.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
30
+ fakesnow-0.9.37.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
31
+ fakesnow-0.9.37.dist-info/top_level.txt,sha256=Yos7YveA3f03xVYuURqnBsfMV2DePXfu_yGcsj3pPzI,30
32
+ fakesnow-0.9.37.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.7.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,29 +0,0 @@
1
- fakesnow/__init__.py,sha256=qUfgucQYPdELrJaxczalhJgWAWQ6cfTCUAHx6nUqRaI,3528
2
- fakesnow/__main__.py,sha256=GDrGyNTvBFuqn_UfDjKs7b3LPtU6gDv1KwosVDrukIM,76
3
- fakesnow/arrow.py,sha256=XjTpFyLrD9jULWOtPgpr0RyNMmO6a5yi82y6ivi2CCI,4884
4
- fakesnow/checks.py,sha256=be-xo0oMoAUVhlMDCu1_Rkoh_L8p_p8qo9P6reJSHIQ,2874
5
- fakesnow/cli.py,sha256=9qfI-Ssr6mo8UmIlXkUAOz2z2YPBgDsrEVaZv9FjGFs,2201
6
- fakesnow/conn.py,sha256=2WClMmUgfQkQA2hFQjfMP3R-85TbTbZh_8Y1tCdcerA,6053
7
- fakesnow/converter.py,sha256=xoBFnfBbGWQyUQAVr6zi-RyglU8A7A3GSlwLPkH1dzI,1621
8
- fakesnow/cursor.py,sha256=e-nY-w25xmLs1jdhIbO6mwzBHVIUKYIkzR37Wnf3Cfc,22068
9
- fakesnow/expr.py,sha256=CAxuYIUkwI339DQIBzvFF0F-m1tcVGKEPA5rDTzmH9A,892
10
- fakesnow/fakes.py,sha256=JQTiUkkwPeQrJ8FDWhPFPK6pGwd_aR2oiOrNzCWznlM,187
11
- fakesnow/fixtures.py,sha256=G-NkVeruSQAJ7fvSS2fR2oysUn0Yra1pohHlOvacKEk,455
12
- fakesnow/info_schema.py,sha256=AYmTIHxk5Y6xdMTgttgBL1V0VO8qiM2T1-gKwkLmWDs,8720
13
- fakesnow/instance.py,sha256=OKoYXwaI6kL9HQpnHx44yzpON_xNfuIT_F4oJNF_XXQ,2114
14
- fakesnow/macros.py,sha256=pX1YJDnQOkFJSHYUjQ6ErEkYIKvFI6Ncz_au0vv1csA,265
15
- fakesnow/pandas_tools.py,sha256=wI203UQHC8JvDzxE_VjE1NeV4rThek2P-u52oTg2foo,3481
16
- fakesnow/py.typed,sha256=B-DLSjYBi7pkKjwxCSdpVj2J02wgfJr-E7B1wOUyxYU,80
17
- fakesnow/rowtype.py,sha256=QUp8EaXD5LT0Xv8BXk5ze4WseEn52xoJ6R05pJjs5mM,2729
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
21
- fakesnow/transforms/merge.py,sha256=Pg7_rwbAT_vr1U4ocBofUSyqaK8_e3qdIz_2SDm2S3s,8320
22
- fakesnow/transforms/show.py,sha256=0NjuLQjodrukfUw8mcxcAmtBkV_6r02mA3nuE3ad3rE,17458
23
- fakesnow-0.9.35.dist-info/licenses/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
24
- tools/decode.py,sha256=kC5kUvLQxdCkMRsnH6BqCajlKxKeN77w6rwCKsY6gqU,1781
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,,