Skip to content

Commit c5dce35

Browse files
SNOW-2267482: Fix flakiness due to SnowAPI dependency (#4190)
1 parent d4e00e4 commit c5dce35

8 files changed

Lines changed: 1435 additions & 326 deletions

File tree

src/snowflake/snowpark/catalog.py

Lines changed: 857 additions & 133 deletions
Large diffs are not rendered by default.

src/snowflake/snowpark/context.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232

3333
# This is an internal-only global flag, used to determine whether the api code which will be executed is compatible with snowflake.snowpark_connect
3434
_is_snowpark_connect_compatible_mode = False
35+
36+
# Default backend selector for the Snowpark Catalog when running in
37+
# Snowpark-Connect / SCOS compatible mode. True -> SQL-based backend,
38+
# False -> legacy snowflake.core REST backend. Read live by Catalog.__init__.
39+
_use_sql_base_catalog = True
3540
# Internal-only global flag that enables improved SQL simplifier query flattening
3641
# for filter, sort, select, and distinct. When True (default), the branch
3742
# improvements are active regardless of _is_snowpark_connect_compatible_mode.

src/snowflake/snowpark/exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,9 @@ class SnowparkInvalidObjectNameException(SnowparkGeneralException):
283283
"""
284284

285285
pass
286+
287+
288+
class _NotFoundError(SnowparkClientException):
289+
"""Internal exception raised when a Snowpark catalog object is not found."""
290+
291+
pass

tests/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from snowflake.snowpark._internal.utils import warning_dict
1515
from .ast.conftest import default_unparser_path
1616

17+
pytest_plugins = ("tests.integ.test_catalog",)
18+
1719
logging.getLogger("snowflake.connector").setLevel(logging.ERROR)
1820

1921
excluded_frontend_files = [

tests/integ/test_catalog.py

Lines changed: 18 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,26 @@
11
#
22
# Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
33
#
4+
"""Catalog integration tests and shared fixtures.
5+
6+
Mode-agnostic tests (same behavior for SQL and REST catalog backends) live in
7+
this module. Backend-specific tests are in ``test_catalog_sql_mode.py`` and
8+
``test_catalog_rest_mode.py``, which reuse the fixtures defined here via
9+
``pytest_plugins`` in ``conftest.py``.
10+
"""
411

5-
from unittest.mock import patch
612
import uuid
13+
from unittest.mock import patch
14+
715
import pytest
816

9-
from snowflake.snowpark._internal.analyzer.analyzer_utils import unquote_if_quoted
1017
from snowflake.snowpark.catalog import Catalog
18+
from snowflake.snowpark.context import _DEFAULT_ARTIFACT_REPOSITORY
1119
from snowflake.snowpark.session import Session
1220
from snowflake.snowpark.types import IntegerType
13-
from snowflake.core.exceptions import APIError
14-
from snowflake.snowpark.context import _DEFAULT_ARTIFACT_REPOSITORY
15-
16-
17-
pytestmark = [
18-
pytest.mark.xfail(
19-
"config.getoption('local_testing_mode', default=False)",
20-
reason="deepcopy is not supported and required by local testing",
21-
run=False,
22-
),
23-
pytest.mark.xfail(
24-
raises=APIError,
25-
reason="Failure due to warehouse overload",
26-
),
27-
]
2821

2922
CATALOG_TEMP_OBJECT_PREFIX = "SP_CATALOG_TEMP"
23+
DOES_NOT_EXIST_PATTERN = "does_not_exist_.*"
3024

3125

3226
def get_temp_name(type: str) -> str:
@@ -186,34 +180,13 @@ def temp_udf2(session, temp_db1, temp_schema1):
186180
)
187181

188182

189-
DOES_NOT_EXIST_PATTERN = "does_not_exist_.*"
190-
191-
192-
def test_list_db(session, temp_db1, temp_db2):
193-
catalog: Catalog = session.catalog
194-
db_list = catalog.list_databases(pattern=f"{CATALOG_TEMP_OBJECT_PREFIX}_DB_*")
195-
assert {db.name for db in db_list} >= {temp_db1, temp_db2}
196-
197-
db_list = catalog.list_databases(like=f"{CATALOG_TEMP_OBJECT_PREFIX}_DB_%")
198-
assert {db.name for db in db_list} >= {temp_db1, temp_db2}
199-
200-
201-
def test_list_schema(session, temp_db1, temp_schema1, temp_schema2):
202-
catalog: Catalog = session.catalog
203-
assert (
204-
len(catalog.list_databases(pattern=f"{CATALOG_TEMP_OBJECT_PREFIX}_SCHEMA_.*"))
205-
== 0
206-
)
207-
208-
schema_list = catalog.list_schemas(
209-
pattern=f"{CATALOG_TEMP_OBJECT_PREFIX}_SCHEMA_.*", database=temp_db1
210-
)
211-
assert {schema.name for schema in schema_list} >= {temp_schema1, temp_schema2}
212-
213-
schema_list = catalog.list_schemas(
214-
like=f"{CATALOG_TEMP_OBJECT_PREFIX}_SCHEMA_%", database=temp_db1
215-
)
216-
assert {schema.name for schema in schema_list} >= {temp_schema1, temp_schema2}
183+
pytestmark = [
184+
pytest.mark.xfail(
185+
"config.getoption('local_testing_mode', default=False)",
186+
reason="deepcopy is not supported and required by local testing",
187+
run=False,
188+
),
189+
]
217190

218191

219192
def test_list_tables(session, temp_db1, temp_schema1, temp_table1, temp_table2):
@@ -344,48 +317,6 @@ def test_list_udfs(session, temp_db1, temp_schema1, temp_udf1, temp_udf2):
344317
assert {udf.name for udf in udf_list} >= {temp_udf1, temp_udf2}
345318

346319

347-
def test_get_db_schema(session):
348-
catalog: Catalog = session.catalog
349-
current_db = session.get_current_database()
350-
current_schema = session.get_current_schema()
351-
assert catalog.get_database(current_db).name == unquote_if_quoted(current_db)
352-
assert catalog.get_schema(current_schema).name == unquote_if_quoted(current_schema)
353-
354-
355-
def test_get_table_view(session, temp_db1, temp_schema1, temp_table1, temp_view1):
356-
catalog: Catalog = session.catalog
357-
table = catalog.get_table(temp_table1, database=temp_db1, schema=temp_schema1)
358-
assert table.name == temp_table1
359-
assert table.database_name == temp_db1
360-
assert table.schema_name == temp_schema1
361-
362-
view = catalog.get_view(temp_view1, database=temp_db1, schema=temp_schema1)
363-
assert view.name == temp_view1
364-
assert view.database_name == temp_db1
365-
assert view.schema_name == temp_schema1
366-
367-
368-
@pytest.mark.udf
369-
def test_get_function_procedure_udf(
370-
session, temp_db1, temp_schema1, temp_procedure1, temp_udf1
371-
):
372-
catalog: Catalog = session.catalog
373-
374-
procedure = catalog.get_procedure(
375-
temp_procedure1, [IntegerType()], database=temp_db1, schema=temp_schema1
376-
)
377-
assert procedure.name == temp_procedure1
378-
assert procedure.database_name == temp_db1
379-
assert procedure.schema_name == temp_schema1
380-
381-
udf = catalog.get_user_defined_function(
382-
temp_udf1, [IntegerType()], database=temp_db1, schema=temp_schema1
383-
)
384-
assert udf.name == temp_udf1
385-
assert udf.database_name == temp_db1
386-
assert udf.schema_name == temp_schema1
387-
388-
389320
def test_set_db_schema(session, temp_db1, temp_db2, temp_schema1, temp_schema2):
390321
catalog = session.catalog
391322

@@ -407,112 +338,6 @@ def test_set_db_schema(session, temp_db1, temp_db2, temp_schema1, temp_schema2):
407338
session.use_schema(original_schema)
408339

409340

410-
def test_exists_db_schema(session, temp_db1, temp_schema1):
411-
catalog = session.catalog
412-
assert catalog.database_exists(temp_db1)
413-
assert not catalog.database_exists("does_not_exist")
414-
415-
assert catalog.schema_exists(temp_schema1, database=temp_db1)
416-
assert not catalog.schema_exists(temp_schema1, database="does_not_exist")
417-
418-
419-
def test_exists_table_view(session, temp_db1, temp_schema1, temp_table1, temp_view1):
420-
catalog = session.catalog
421-
db1_obj = catalog._root.databases[temp_db1].fetch()
422-
schema1_obj = catalog._root.databases[temp_db1].schemas[temp_schema1].fetch()
423-
424-
assert catalog.table_exists(temp_table1, database=temp_db1, schema=temp_schema1)
425-
assert catalog.table_exists(temp_table1, database=db1_obj, schema=schema1_obj)
426-
table = catalog.get_table(temp_table1, database=temp_db1, schema=temp_schema1)
427-
assert catalog.table_exists(table)
428-
assert not catalog.table_exists(
429-
"does_not_exist", database=temp_db1, schema=temp_schema1
430-
)
431-
432-
assert catalog.view_exists(temp_view1, database=temp_db1, schema=temp_schema1)
433-
assert catalog.view_exists(temp_view1, database=db1_obj, schema=schema1_obj)
434-
view = catalog.get_view(temp_view1, database=temp_db1, schema=temp_schema1)
435-
assert catalog.view_exists(view)
436-
assert not catalog.view_exists(
437-
"does_not_exist", database=temp_db1, schema=temp_schema1
438-
)
439-
440-
441-
@pytest.mark.udf
442-
def test_exists_function_procedure_udf(
443-
session, temp_db1, temp_schema1, temp_procedure1, temp_udf1
444-
):
445-
catalog = session.catalog
446-
db1_obj = catalog._root.databases[temp_db1].fetch()
447-
schema1_obj = catalog._root.databases[temp_db1].schemas[temp_schema1].fetch()
448-
449-
assert catalog.procedure_exists(
450-
temp_procedure1, [IntegerType()], database=temp_db1, schema=temp_schema1
451-
)
452-
assert catalog.procedure_exists(
453-
temp_procedure1, [IntegerType()], database=db1_obj, schema=schema1_obj
454-
)
455-
proc = catalog.get_procedure(
456-
temp_procedure1, [IntegerType()], database=temp_db1, schema=temp_schema1
457-
)
458-
assert catalog.procedure_exists(proc)
459-
assert not catalog.procedure_exists(
460-
"does_not_exist", [], database=temp_db1, schema=temp_schema1
461-
)
462-
463-
assert catalog.user_defined_function_exists(
464-
temp_udf1, [IntegerType()], database=temp_db1, schema=temp_schema1
465-
)
466-
assert catalog.user_defined_function_exists(
467-
temp_udf1, [IntegerType()], database=db1_obj, schema=schema1_obj
468-
)
469-
udf = catalog.get_user_defined_function(
470-
temp_udf1, [IntegerType()], database=temp_db1, schema=temp_schema1
471-
)
472-
assert catalog.user_defined_function_exists(udf)
473-
assert not catalog.user_defined_function_exists(
474-
"does_not_exist", [], database=temp_db1, schema=temp_schema1
475-
)
476-
477-
478-
@pytest.mark.parametrize("use_object", [True, False])
479-
def test_drop(session, use_object):
480-
catalog = session.catalog
481-
482-
original_db = session.get_current_database()
483-
original_schema = session.get_current_schema()
484-
try:
485-
temp_db = create_temp_db(session)
486-
temp_schema = create_temp_schema(session, temp_db)
487-
temp_table = create_temp_table(session, temp_db, temp_schema)
488-
temp_view = create_temp_view(session, temp_db, temp_schema)
489-
if use_object:
490-
temp_schema = catalog._root.databases[temp_db].schemas[temp_schema].fetch()
491-
temp_db = catalog._root.databases[temp_db].fetch()
492-
493-
assert catalog.database_exists(temp_db)
494-
assert catalog.schema_exists(temp_schema, database=temp_db)
495-
assert catalog.table_exists(temp_table, database=temp_db, schema=temp_schema)
496-
assert catalog.view_exists(temp_view, database=temp_db, schema=temp_schema)
497-
498-
catalog.drop_table(temp_table, database=temp_db, schema=temp_schema)
499-
catalog.drop_view(temp_view, database=temp_db, schema=temp_schema)
500-
501-
assert not catalog.table_exists(
502-
temp_table, database=temp_db, schema=temp_schema
503-
)
504-
assert not catalog.view_exists(temp_view, database=temp_db, schema=temp_schema)
505-
506-
catalog.drop_schema(temp_schema, database=temp_db)
507-
assert not catalog.schema_exists(temp_schema, database=temp_db)
508-
509-
catalog.drop_database(temp_db)
510-
assert not catalog.database_exists(temp_db)
511-
finally:
512-
session.use_database(original_db)
513-
session.use_schema(original_schema)
514-
515-
516341
def test_parse_names_negative(session):
517342
catalog = session.catalog
518343
with pytest.raises(

0 commit comments

Comments
 (0)