Expected
A unit test should succeed when run separately from the rest of the test suite in which it is contained.
Observed
The test_sql_variant test in tests/sqlserver_test.py fails when run independently.
% pytest tests/sqlserver_test.py
============================================= test session starts ==============================================
platform darwin -- Python 3.14.0, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/bkline/repos/pyodbc
configfile: pyproject.toml
collected 98 items
tests/sqlserver_test.py ................................................................................ [ 81%]
.................. [100%]
============================================== 98 passed in 3.41s ==============================================
% pytest tests/sqlserver_test.py::test_sql_variant
============================================= test session starts ==============================================
platform darwin -- Python 3.14.0, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/bkline/repos/pyodbc
configfile: pyproject.toml
collected 1 item
tests/sqlserver_test.py F
=================================================== FAILURES ===================================================
_______________________________________________ test_sql_variant _______________________________________________
cursor = <pyodbc.Cursor object at 0x1075e7830>
@pytest.mark.skipif(SQLSERVER_YEAR < 2000, reason='sql_variant not supported until 2000')
def test_sql_variant(cursor: pyodbc.Cursor):
"""
Tests decoding of the sql_variant data type as performed by the GetData_SqlVariant() method.
"""
cursor.execute("create table t1 (a sql_variant)")
# insert a number of values of disparate types. this is not exhaustive as not all
# types that can be contained within a sql_variant field are supported by pyodbc
cursor.execute("insert into t1 values (456.7)")
cursor.execute("insert into t1 values ('a string')")
cursor.execute("insert into t1 values (CAST('2024-06-03' AS DATE))")
cursor.execute("insert into t1 values (CAST('2024-06-03 23:46:03.000' AS DATETIME))")
cursor.execute("insert into t1 values (CAST('binary data' AS VARBINARY(200)))")
cursor.execute(
"insert into t1 values (CAST('0592b437-745f-4b2c-a997-97022c624cf6' AS UNIQUEIDENTIFIER))"
)
# select all of the values we inserted and ensure they have the correct types
results = [record[0] for record in cursor.execute("select a from t1").fetchall()]
for index, assertion_tuple in enumerate(
[
(Decimal, Decimal("456.7")),
(str, "a string"),
(date, date(2024, 6, 3)),
(datetime, datetime(2024, 6, 3, 23, 46, 3)),
(bytes, b'binary data'),
(uuid.UUID, uuid.UUID("0592b437-745f-4b2c-a997-97022c624cf6"))
]
):
# pylint: disable=unidiomatic-typecheck
expected_type, expected_value = assertion_tuple
> assert type(results[index]) is expected_type
E AssertionError: assert <class 'str'> is <class 'uuid.UUID'>
E + where <class 'str'> = type('0592B437-745F-4B2C-A997-97022C624CF6')
tests/sqlserver_test.py:1682: AssertionError
=========================================== short test summary info ============================================
FAILED tests/sqlserver_test.py::test_sql_variant - AssertionError: assert <class 'str'> is <class 'uuid.UUID'>
============================================== 1 failed in 0.27s ===============================================
Environment
| Component |
Version |
| pyodbc |
5.3.0 |
| Database |
Microsoft SQL Server 2022 (RTM-CU24) (KB5080999) - 16.0.4245.2 (X64) |
| OS |
macOS 26.3.1, Ubuntu 24.04, and Windows 11 [10.0.26200.8037] |
Analysis
The documentation says
native_uuid
A Boolean that determines whether SQL_GUID columns, e.g. UNIQUEIDENTIFIER or UUID, are returned as text (with False, the default) or as uuid.UUID objects (with True). The default is False for backwards compatibility, but this may change in a future release.
Several tests modify pyodbc.native_uuid without restoring it to its original value. The implementation of test_sql_variant assumes that the last of those tests to have run will have left the flag turned on. That doesn't necessarily happen when the tests to be executed for a given run are specified explicitly, thus the failure of test_sql_variant. To add to the confusion, the comments on the tests disagree about what the default value is for the property, claiming False as the default in some places, but True elsewhere. One comment even claims that the flag will be reset, which never happens.
Remedy
- Explicitly set
pyodbc.native_uuid to the value assumed by the test wherever that value can affect the test's observed behavior.
- Always save the original value of
pyodbc.native_uuid before assigning a (possibly new) value.
- Always restore the original value of
pyodbc.native_uuid when it has been explicitly assigned for a test.
- Remove comments identifying the default for
pyodbc.native_uuid (which may change at some point) from the tests.
Expected
A unit test should succeed when run separately from the rest of the test suite in which it is contained.
Observed
The
test_sql_varianttest intests/sqlserver_test.pyfails when run independently.Environment
Analysis
The documentation says
Several tests modify
pyodbc.native_uuidwithout restoring it to its original value. The implementation oftest_sql_variantassumes that the last of those tests to have run will have left the flag turned on. That doesn't necessarily happen when the tests to be executed for a given run are specified explicitly, thus the failure oftest_sql_variant. To add to the confusion, the comments on the tests disagree about what the default value is for the property, claimingFalseas the default in some places, butTrueelsewhere. One comment even claims that the flag will be reset, which never happens.Remedy
pyodbc.native_uuidto the value assumed by the test wherever that value can affect the test's observed behavior.pyodbc.native_uuidbefore assigning a (possibly new) value.pyodbc.native_uuidwhen it has been explicitly assigned for a test.pyodbc.native_uuid(which may change at some point) from the tests.