diff options
| author | Federico Caselli <cfederico87@gmail.com> | 2022-06-03 14:51:04 +0200 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-06-07 12:59:57 -0400 |
| commit | fcbdae075bb3f3a4ecc9b36e5787bba6b80af9c1 (patch) | |
| tree | 1df26ffe2f4dece2cc6df4e58cdaee157a2fc010 /test | |
| parent | ad86d32f7fbd1c6deda8ff3bebe0595c0f2986cc (diff) | |
| download | sqlalchemy-fcbdae075bb3f3a4ecc9b36e5787bba6b80af9c1.tar.gz | |
Add support for the new oracle driver ``oracledb``.
Fixes: #8054
Change-Id: Idd7c1bbb7ca39499f53bdf59a63a6a9d65f144a5
Diffstat (limited to 'test')
| -rw-r--r-- | test/dialect/oracle/_oracledb_mode.py | 30 | ||||
| -rw-r--r-- | test/dialect/oracle/test_compiler.py | 6 | ||||
| -rw-r--r-- | test/dialect/oracle/test_dialect.py | 230 | ||||
| -rw-r--r-- | test/dialect/oracle/test_types.py | 28 | ||||
| -rw-r--r-- | test/engine/test_execute.py | 4 | ||||
| -rw-r--r-- | test/engine/test_reconnect.py | 4 | ||||
| -rw-r--r-- | test/orm/test_unitofwork.py | 1 | ||||
| -rw-r--r-- | test/requirements.py | 73 |
8 files changed, 268 insertions, 108 deletions
diff --git a/test/dialect/oracle/_oracledb_mode.py b/test/dialect/oracle/_oracledb_mode.py new file mode 100644 index 000000000..21743d6ec --- /dev/null +++ b/test/dialect/oracle/_oracledb_mode.py @@ -0,0 +1,30 @@ +# do not import sqlalchemy testing feature in this file, since it's +# run directly, not passing through pytest +from sqlalchemy import create_engine + + +def _get_version(conn): + # this is the suggested way of finding the mode, from + # https://python-oracledb.readthedocs.io/en/latest/user_guide/tracing.html#vsessconinfo + sql = ( + "SELECT UNIQUE CLIENT_DRIVER " + "FROM V$SESSION_CONNECT_INFO " + "WHERE SID = SYS_CONTEXT('USERENV', 'SID')" + ) + return conn.exec_driver_sql(sql).scalar() + + +def run_thin_mode(url, queue): + e = create_engine(url) + with e.connect() as conn: + res = _get_version(conn) + queue.put((res, e.dialect.is_thin_mode(conn))) + e.dispose() + + +def run_thick_mode(url, queue): + e = create_engine(url, thick_mode={"driver_name": "custom-driver-name"}) + with e.connect() as conn: + res = _get_version(conn) + queue.put((res, e.dialect.is_thin_mode(conn))) + e.dispose() diff --git a/test/dialect/oracle/test_compiler.py b/test/dialect/oracle/test_compiler.py index c506c306e..ecf43a2cf 100644 --- a/test/dialect/oracle/test_compiler.py +++ b/test/dialect/oracle/test_compiler.py @@ -28,6 +28,7 @@ from sqlalchemy import types as sqltypes from sqlalchemy import union from sqlalchemy.dialects.oracle import base as oracle from sqlalchemy.dialects.oracle import cx_oracle +from sqlalchemy.dialects.oracle import oracledb from sqlalchemy.engine import default from sqlalchemy.sql import column from sqlalchemy.sql import ddl @@ -106,6 +107,11 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): "(__[POSTCOMPILE_uid])", dialect=cx_oracle.dialect(), ) + self.assert_compile( + bindparam("uid", expanding=True), + "(__[POSTCOMPILE_uid])", + dialect=oracledb.dialect(), + ) def test_cte(self): part = table( diff --git a/test/dialect/oracle/test_dialect.py b/test/dialect/oracle/test_dialect.py index 8d74c1f48..f9851ee94 100644 --- a/test/dialect/oracle/test_dialect.py +++ b/test/dialect/oracle/test_dialect.py @@ -1,5 +1,6 @@ # coding: utf-8 +from multiprocessing import get_context import re from unittest import mock from unittest.mock import Mock @@ -23,6 +24,7 @@ from sqlalchemy import Unicode from sqlalchemy import UnicodeText from sqlalchemy.dialects.oracle import base as oracle from sqlalchemy.dialects.oracle import cx_oracle +from sqlalchemy.dialects.oracle import oracledb from sqlalchemy.engine import url from sqlalchemy.testing import assert_raises from sqlalchemy.testing import assert_raises_message @@ -32,6 +34,8 @@ from sqlalchemy.testing import config from sqlalchemy.testing import engines from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures +from sqlalchemy.testing import is_false +from sqlalchemy.testing import is_true from sqlalchemy.testing.assertions import expect_raises_message from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import pep435_enum @@ -39,35 +43,85 @@ from sqlalchemy.testing.schema import Table from sqlalchemy.testing.suite import test_select -class DialectTest(fixtures.TestBase): +class CxOracleDialectTest(fixtures.TestBase): def test_cx_oracle_version_parse(self): dialect = cx_oracle.OracleDialect_cx_oracle() - eq_(dialect._parse_cx_oracle_ver("5.2"), (5, 2)) + def check(version): + dbapi = Mock(version=version) + dialect._load_version(dbapi) + return dialect.cx_oracle_ver - eq_(dialect._parse_cx_oracle_ver("5.0.1"), (5, 0, 1)) - - eq_(dialect._parse_cx_oracle_ver("6.0b1"), (6, 0)) + eq_(check("7.2"), (7, 2)) + eq_(check("7.0.1"), (7, 0, 1)) + eq_(check("9.0b1"), (9, 0)) def test_minimum_version(self): - with mock.patch( - "sqlalchemy.dialects.oracle.cx_oracle.OracleDialect_cx_oracle." - "_parse_cx_oracle_ver", - lambda self, vers: (5, 1, 5), + with expect_raises_message( + exc.InvalidRequestError, + "cx_Oracle version 7 and above are supported", ): - assert_raises_message( - exc.InvalidRequestError, - "cx_Oracle version 7 and above are supported", - cx_oracle.OracleDialect_cx_oracle, - dbapi=mock.Mock(), - ) + cx_oracle.OracleDialect_cx_oracle(dbapi=Mock(version="5.1.5")) + + dialect = cx_oracle.OracleDialect_cx_oracle( + dbapi=Mock(version="7.1.0") + ) + eq_(dialect.cx_oracle_ver, (7, 1, 0)) + + +class OracleDbDialectTest(fixtures.TestBase): + def test_oracledb_version_parse(self): + dialect = oracledb.OracleDialect_oracledb() - with mock.patch( - "sqlalchemy.dialects.oracle.cx_oracle.OracleDialect_cx_oracle." - "_parse_cx_oracle_ver", - lambda self, vers: (7, 1, 0), + def check(version): + dbapi = Mock(version=version) + dialect._load_version(dbapi) + return dialect.oracledb_ver + + eq_(check("7.2"), (7, 2)) + eq_(check("7.0.1"), (7, 0, 1)) + eq_(check("9.0b1"), (9, 0)) + + def test_minimum_version(self): + with expect_raises_message( + exc.InvalidRequestError, + "oracledb version 1 and above are supported", ): - cx_oracle.OracleDialect_cx_oracle(dbapi=mock.Mock()) + oracledb.OracleDialect_oracledb(dbapi=Mock(version="0.1.5")) + + dialect = oracledb.OracleDialect_oracledb(dbapi=Mock(version="7.1.0")) + eq_(dialect.oracledb_ver, (7, 1, 0)) + + +class OracledbMode(fixtures.TestBase): + __backend__ = True + __only_on__ = "oracle+oracledb" + + def _run_in_process(self, fn): + ctx = get_context("spawn") + queue = ctx.Queue() + process = ctx.Process(target=fn, args=(str(config.db_url), queue)) + try: + process.start() + process.join(10) + eq_(process.exitcode, 0) + return queue.get_nowait() + finally: + process.kill() + + def test_thin_mode(self): + from ._oracledb_mode import run_thin_mode + + mode, is_thin = self._run_in_process(run_thin_mode) + is_true(is_thin) + is_true(mode.startswith("python-oracledb thn")) + + def test_thick_mode(self): + from ._oracledb_mode import run_thick_mode + + mode, is_thin = self._run_in_process(run_thick_mode) + is_false(is_thin) + eq_(mode.strip(), "custom-driver-name") class DialectWBackendTest(fixtures.TestBase): @@ -111,7 +165,7 @@ class DialectWBackendTest(fixtures.TestBase): False, ), ) - @testing.only_on("oracle+cx_oracle") + @testing.only_on(["oracle+cx_oracle", "oracle+oracledb"]) def test_is_disconnect(self, message, code, expected): dialect = testing.db.dialect @@ -289,6 +343,9 @@ class EncodingErrorsTest(fixtures.TestBase): argnames="cx_oracle_type", id_="ia", ) + _dialect = testing.combinations( + cx_oracle.dialect, oracledb.dialect, argnames="dialect_cls" + ) def _assert_errorhandler(self, outconverter, has_errorhandler): data = "\uee2c\u9a66" # this is u"\uee2c\u9a66" @@ -305,14 +362,11 @@ class EncodingErrorsTest(fixtures.TestBase): assert_raises(UnicodeDecodeError, outconverter, utf8_w_errors) @_oracle_char_combinations + @_dialect def test_encoding_errors_cx_oracle( - self, - cx_Oracle, - cx_oracle_type, + self, cx_Oracle, cx_oracle_type, dialect_cls ): - ignore_dialect = cx_oracle.dialect( - dbapi=cx_Oracle, encoding_errors="ignore" - ) + ignore_dialect = dialect_cls(dbapi=cx_Oracle, encoding_errors="ignore") ignore_outputhandler = ( ignore_dialect._generate_connection_outputtype_handler() @@ -334,12 +388,11 @@ class EncodingErrorsTest(fixtures.TestBase): ) @_oracle_char_combinations + @_dialect def test_no_encoding_errors_cx_oracle( - self, - cx_Oracle, - cx_oracle_type, + self, cx_Oracle, cx_oracle_type, dialect_cls ): - plain_dialect = cx_oracle.dialect(dbapi=cx_Oracle) + plain_dialect = dialect_cls(dbapi=cx_Oracle) plain_outputhandler = ( plain_dialect._generate_connection_outputtype_handler() @@ -433,7 +486,7 @@ class ComputedReturningTest(fixtures.TablesTest): class OutParamTest(fixtures.TestBase, AssertsExecutionResults): - __only_on__ = "oracle+cx_oracle" + __only_on__ = ("oracle+cx_oracle", "oracle+oracledb") __backend__ = True @classmethod @@ -877,12 +930,21 @@ class UnicodeSchemaTest(fixtures.TestBase): eq_(result, "’é") -class CXOracleConnectArgsTest(fixtures.TestBase): - __only_on__ = "oracle+cx_oracle" - __backend__ = True +class BaseConnectArgsTest: + @property + def name(self): + raise NotImplementedError + + @property + def dbapi(self): + raise NotImplementedError + + @property + def dialect_cls(self): + raise NotImplementedError def test_cx_oracle_service_name(self): - url_string = "oracle+cx_oracle://scott:tiger@host/?service_name=hr" + url_string = f"oracle+{self.name}://scott:tiger@host/?service_name=hr" eng = create_engine(url_string, _initialize=False) cargs, cparams = eng.dialect.create_connect_args(eng.url) @@ -890,7 +952,9 @@ class CXOracleConnectArgsTest(fixtures.TestBase): assert "SID=hr" not in cparams["dsn"] def test_cx_oracle_service_name_bad(self): - url_string = "oracle+cx_oracle://scott:tiger@host/hr1?service_name=hr2" + url_string = ( + f"oracle+{self.name}://scott:tiger@host/hr1?service_name=hr2" + ) assert_raises( exc.InvalidRequestError, create_engine, @@ -899,69 +963,59 @@ class CXOracleConnectArgsTest(fixtures.TestBase): ) def _test_db_opt(self, url_string, key, value): - import cx_Oracle - url_obj = url.make_url(url_string) - dialect = cx_oracle.dialect(dbapi=cx_Oracle) + dialect = self.dialect_cls(dbapi=self.dbapi) arg, kw = dialect.create_connect_args(url_obj) eq_(kw[key], value) def _test_db_opt_unpresent(self, url_string, key): - import cx_Oracle - url_obj = url.make_url(url_string) - dialect = cx_oracle.dialect(dbapi=cx_Oracle) + dialect = self.dialect_cls(dbapi=self.dbapi) arg, kw = dialect.create_connect_args(url_obj) assert key not in kw def _test_dialect_param_from_url(self, url_string, key, value): - import cx_Oracle - url_obj = url.make_url(url_string) - dialect = cx_oracle.dialect(dbapi=cx_Oracle) + dialect = self.dialect_cls(dbapi=self.dbapi) with testing.expect_deprecated( - "cx_oracle dialect option %r should" % key + f"{self.name} dialect option %r should" % key ): arg, kw = dialect.create_connect_args(url_obj) eq_(getattr(dialect, key), value) # test setting it on the dialect normally - dialect = cx_oracle.dialect(dbapi=cx_Oracle, **{key: value}) + dialect = self.dialect_cls(dbapi=self.dbapi, **{key: value}) eq_(getattr(dialect, key), value) def test_mode(self): - import cx_Oracle - self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?mode=sYsDBA", + f"oracle+{self.name}://scott:tiger@host/?mode=sYsDBA", "mode", - cx_Oracle.SYSDBA, + self.dbapi.SYSDBA, ) self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?mode=SYSOPER", + f"oracle+{self.name}://scott:tiger@host/?mode=SYSOPER", "mode", - cx_Oracle.SYSOPER, + self.dbapi.SYSOPER, ) def test_int_mode(self): self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?mode=32767", "mode", 32767 + f"oracle+{self.name}://scott:tiger@host/?mode=32767", "mode", 32767 ) @testing.requires.cxoracle6_or_greater def test_purity(self): - import cx_Oracle - self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?purity=attr_purity_new", + f"oracle+{self.name}://scott:tiger@host/?purity=attr_purity_new", "purity", - cx_Oracle.ATTR_PURITY_NEW, + self.dbapi.ATTR_PURITY_NEW, ) def test_encoding(self): self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/" + f"oracle+{self.name}://scott:tiger@host/" "?encoding=AMERICAN_AMERICA.UTF8", "encoding", "AMERICAN_AMERICA.UTF8", @@ -969,45 +1023,85 @@ class CXOracleConnectArgsTest(fixtures.TestBase): def test_threaded(self): self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?threaded=true", + f"oracle+{self.name}://scott:tiger@host/?threaded=true", "threaded", True, ) self._test_db_opt_unpresent( - "oracle+cx_oracle://scott:tiger@host/", "threaded" + f"oracle+{self.name}://scott:tiger@host/", "threaded" ) def test_events(self): self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?events=true", "events", True + f"oracle+{self.name}://scott:tiger@host/?events=true", + "events", + True, ) def test_threaded_deprecated_at_dialect_level(self): with testing.expect_deprecated( - "The 'threaded' parameter to the cx_oracle dialect" + "The 'threaded' parameter to the cx_oracle/oracledb dialect" ): - dialect = cx_oracle.dialect(threaded=False) + dialect = self.dialect_cls(threaded=False) arg, kw = dialect.create_connect_args( - url.make_url("oracle+cx_oracle://scott:tiger@dsn") + url.make_url(f"oracle+{self.name}://scott:tiger@dsn") ) eq_(kw["threaded"], False) def test_deprecated_use_ansi(self): self._test_dialect_param_from_url( - "oracle+cx_oracle://scott:tiger@host/?use_ansi=False", + f"oracle+{self.name}://scott:tiger@host/?use_ansi=False", "use_ansi", False, ) def test_deprecated_auto_convert_lobs(self): self._test_dialect_param_from_url( - "oracle+cx_oracle://scott:tiger@host/?auto_convert_lobs=False", + f"oracle+{self.name}://scott:tiger@host/?auto_convert_lobs=False", "auto_convert_lobs", False, ) +class CXOracleConnectArgsTest(BaseConnectArgsTest, fixtures.TestBase): + __only_on__ = "oracle+cx_oracle" + __backend__ = True + + @property + def name(self): + return "cx_oracle" + + @property + def dbapi(self): + import cx_Oracle + + return cx_Oracle + + @property + def dialect_cls(self): + return cx_oracle.dialect + + +class OracleDbConnectArgsTest(BaseConnectArgsTest, fixtures.TestBase): + __only_on__ = "oracle+oracledb" + __backend__ = True + + @property + def name(self): + return "oracledb" + + @property + def dbapi(self): + import oracledb + + return oracledb + + @property + def dialect_cls(self): + return oracledb.dialect + + class TableValuedTest(fixtures.TestBase): __backend__ = True __only_on__ = "oracle" diff --git a/test/dialect/oracle/test_types.py b/test/dialect/oracle/test_types.py index 799a5e7b6..cc5dba15d 100644 --- a/test/dialect/oracle/test_types.py +++ b/test/dialect/oracle/test_types.py @@ -39,6 +39,7 @@ from sqlalchemy import UnicodeText from sqlalchemy import VARCHAR from sqlalchemy.dialects.oracle import base as oracle from sqlalchemy.dialects.oracle import cx_oracle +from sqlalchemy.dialects.oracle import oracledb from sqlalchemy.sql import column from sqlalchemy.sql.sqltypes import NullType from sqlalchemy.testing import assert_raises_message @@ -98,9 +99,11 @@ class DialectTypesTest(fixtures.TestBase, AssertsCompiledSQL): (NCHAR(), cx_oracle._OracleNChar), (NVARCHAR(), cx_oracle._OracleUnicodeStringNCHAR), (oracle.RAW(50), cx_oracle._OracleRaw), + argnames="start, test", ) - def test_type_adapt(self, start, test): - dialect = cx_oracle.dialect() + @testing.combinations(cx_oracle, oracledb, argnames="module") + def test_type_adapt(self, start, test, module): + dialect = module.dialect() assert isinstance( start.dialect_impl(dialect), test @@ -115,9 +118,11 @@ class DialectTypesTest(fixtures.TestBase, AssertsCompiledSQL): (UnicodeText(), cx_oracle._OracleUnicodeTextNCLOB), (NCHAR(), cx_oracle._OracleNChar), (NVARCHAR(), cx_oracle._OracleUnicodeStringNCHAR), + argnames="start, test", ) - def test_type_adapt_nchar(self, start, test): - dialect = cx_oracle.dialect(use_nchar_for_unicode=True) + @testing.combinations(cx_oracle, oracledb, argnames="module") + def test_type_adapt_nchar(self, start, test, module): + dialect = module.dialect(use_nchar_for_unicode=True) assert isinstance( start.dialect_impl(dialect), test @@ -723,7 +728,10 @@ class TypesTest(fixtures.TestBase): "SELECT CAST(-9999999999999999999 AS NUMBER(19,0)) FROM dual", ), ) - @testing.only_on("oracle+cx_oracle", "cx_oracle-specific feature") + @testing.only_on( + ["oracle+cx_oracle", "oracle+oracledb"], + "cx_oracle/oracledb specific feature", + ) def test_raw_numerics(self, title, stmt): with testing.db.connect() as conn: # get a brand new connection that definitely is not @@ -797,7 +805,7 @@ class TypesTest(fixtures.TestBase): assert isinstance(t2.c.nv_data.type, sqltypes.NVARCHAR) assert isinstance(t2.c.c_data.type, sqltypes.NCHAR) - if testing.against("oracle+cx_oracle"): + if testing.against("oracle+cx_oracle", "oracle+oracledb"): assert isinstance( t2.c.nv_data.type.dialect_impl(connection.dialect), cx_oracle._OracleUnicodeStringNCHAR, @@ -823,7 +831,7 @@ class TypesTest(fixtures.TestBase): t2 = Table("tnv", m2, autoload_with=connection) assert isinstance(t2.c.data.type, sqltypes.VARCHAR) - if testing.against("oracle+cx_oracle"): + if testing.against("oracle+cx_oracle", "oracle+oracledb"): assert isinstance( t2.c.data.type.dialect_impl(connection.dialect), cx_oracle._OracleString, @@ -1089,7 +1097,7 @@ class EuroNumericTest(fixtures.TestBase): test the numeric output_type_handler when using non-US locale for NLS_LANG. """ - __only_on__ = "oracle+cx_oracle" + __only_on__ = ("oracle+cx_oracle", "oracle+oracledb") __backend__ = True def setup_test(self): @@ -1107,6 +1115,8 @@ class EuroNumericTest(fixtures.TestBase): def teardown_test(self): self.engine.dispose() + # https://python-oracledb.readthedocs.io/en/latest/user_guide/appendix_b.html#globalization-in-thin-and-thick-modes + @testing.requires.fail_on_oracledb_thin def test_were_getting_a_comma(self): connection = self.engine.pool._creator() cursor = connection.cursor() @@ -1166,7 +1176,7 @@ class EuroNumericTest(fixtures.TestBase): class SetInputSizesTest(fixtures.TestBase): - __only_on__ = "oracle+cx_oracle" + __only_on__ = ("oracle+cx_oracle", "oracle+oracledb") __backend__ = True @testing.combinations( diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 7f662bc6e..196b70340 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -562,6 +562,10 @@ class ExecuteTest(fixtures.TablesTest): "oracle+cx_oracle", "cx_oracle exception seems to be having some issue with pickling", ) + @testing.fails_on( + "oracle+oracledb", + "oracledb exception seems to be having some issue with pickling", + ) def test_stmt_exception_pickleable_plus_dbapi(self): raw = testing.db.raw_connection() the_orig = None diff --git a/test/engine/test_reconnect.py b/test/engine/test_reconnect.py index 703cfa8a6..2a6b21e6b 100644 --- a/test/engine/test_reconnect.py +++ b/test/engine/test_reconnect.py @@ -1360,10 +1360,6 @@ class InvalidateDuringResultTest(fixtures.TestBase): self.meta.drop_all(conn) self.engine.dispose() - @testing.crashes( - "oracle", - "cx_oracle 6 doesn't allow a close like this due to open cursors", - ) @testing.fails_if( [ "+mysqlconnector", diff --git a/test/orm/test_unitofwork.py b/test/orm/test_unitofwork.py index 39223a355..0c5933884 100644 --- a/test/orm/test_unitofwork.py +++ b/test/orm/test_unitofwork.py @@ -1187,7 +1187,6 @@ class DefaultTest(fixtures.MappedTest): self.assert_(h2.foober == h3.foober == h4.foober == "im foober") eq_(h5.foober, "im the new foober") - @testing.fails_on("oracle+cx_oracle", "seems like a cx_oracle bug") def test_eager_defaults(self): hohoval, default_t, Hoho = ( self.other.hohoval, diff --git a/test/requirements.py b/test/requirements.py index f5cbbbf8d..452306daa 100644 --- a/test/requirements.py +++ b/test/requirements.py @@ -198,7 +198,7 @@ class DefaultRequirements(SuiteRequirements): @property def named_paramstyle(self): - return only_on(["sqlite", "oracle+cx_oracle"]) + return only_on(["sqlite", "oracle+cx_oracle", "oracle+oracledb"]) @property def format_paramstyle(self): @@ -751,27 +751,32 @@ class DefaultRequirements(SuiteRequirements): else: return num > 0 - return skip_if( - [ - no_support("mssql", "two-phase xact not supported by drivers"), - no_support( - "sqlite", "two-phase xact not supported by database" - ), - # in Ia3cbbf56d4882fcc7980f90519412f1711fae74d - # we are evaluating which modern MySQL / MariaDB versions - # can handle two-phase testing without too many problems - # no_support( - # "mysql", - # "recent MySQL communiity editions have too many issues " - # "(late 2016), disabling for now", - # ), - NotPredicate( - LambdaPredicate( - pg_prepared_transaction, - "max_prepared_transactions not available or zero", - ) - ), - ] + return ( + skip_if( + [ + no_support( + "mssql", "two-phase xact not supported by drivers" + ), + no_support( + "sqlite", "two-phase xact not supported by database" + ), + # in Ia3cbbf56d4882fcc7980f90519412f1711fae74d + # we are evaluating which modern MySQL / MariaDB versions + # can handle two-phase testing without too many problems + # no_support( + # "mysql", + # "recent MySQL community editions have too many " + # "issues (late 2016), disabling for now", + # ), + NotPredicate( + LambdaPredicate( + pg_prepared_transaction, + "max_prepared_transactions not available or zero", + ) + ), + ] + ) + + self.fail_on_oracledb_thin ) @property @@ -1609,10 +1614,16 @@ class DefaultRequirements(SuiteRequirements): @property def cxoracle6_or_greater(self): - return only_if( - lambda config: against(config, "oracle+cx_oracle") - and config.db.dialect.cx_oracle_ver >= (6,) - ) + def go(config): + return ( + against(config, "oracle+cx_oracle") + and config.db.dialect.cx_oracle_ver >= (6,) + ) or ( + against(config, "oracle+oracledb") + and config.db.dialect.oracledb_ver >= (1,) + ) + + return only_if(go) @property def oracle5x(self): @@ -1622,6 +1633,16 @@ class DefaultRequirements(SuiteRequirements): ) @property + def fail_on_oracledb_thin(self): + def go(config): + if against(config, "oracle+oracledb"): + with config.db.connect() as conn: + return config.db.dialect.is_thin_mode(conn) + return False + + return fails_if(go) + + @property def computed_columns(self): return skip_if(["postgresql < 12", "sqlite < 3.31", "mysql < 5.7"]) |
