From 9bc0af30152e7b3a74aa79ecd4d1d297268effd3 Mon Sep 17 00:00:00 2001 From: Balram Choudhary Date: Tue, 23 Dec 2025 16:39:30 +0530 Subject: [PATCH] Fix TupleType import failure across SQLAlchemy versions Signed-off-by: Balram Choudhary --- README.md | 6 +++- ibm_db_sa/base.py | 91 +++++++++++++++++++++++++++++++---------------- 2 files changed, 65 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 9fd659c..09dfae0 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,8 @@ A TCP/IP connection can be specified as the following:: from sqlalchemy import create_engine e = create_engine("db2+ibm_db://user:pass@host[:port]/database") + or + e = create_engine("ibm_db_sa://user:pass@host[:port]/database") ``` For a local socket connection, exclude the "host" and "port" portions:: @@ -77,11 +79,13 @@ For a local socket connection, exclude the "host" and "port" portions:: from sqlalchemy import create_engine e = create_engine("db2+ibm_db://user:pass@/database") + or + e = create_engine("ibm_db_sa://user:pass@/database") ``` Supported Databases ------------------- -- IBM DB2 Universal Database for Linux/Unix/Windows versions 9.7 onwards +- IBM DB2 Database for Linux/Unix/Windows versions 11.5 onwards - IBM Db2 on Cloud - IBM Db2 on ZOS - IBM Db2 on Iseries diff --git a/ibm_db_sa/base.py b/ibm_db_sa/base.py index 50668f7..e96640c 100644 --- a/ibm_db_sa/base.py +++ b/ibm_db_sa/base.py @@ -35,38 +35,67 @@ m = re.match(r"^\s*(\d+)\.(\d+)", SA_VERSION_STR) SA_VERSION_MM = (int(m.group(1)), int(m.group(2))) if m else (0, 0) +# SQLAlchemy >= 2.0 if SA_VERSION_MM >= (2, 0): - from sqlalchemy.sql.sqltypes import NullType, NULLTYPE, _Binary - from sqlalchemy.sql.sqltypes import ( - ARRAY, BIGINT, BigInteger, BINARY, BLOB, BOOLEAN, Boolean, - CHAR, CLOB, Concatenable, DATE, Date, DATETIME, DateTime, - DECIMAL, DOUBLE, Double, DOUBLE_PRECISION, Enum, FLOAT, Float, - Indexable, INT, INTEGER, Integer, Interval, JSON, LargeBinary, - MatchType, NCHAR, NUMERIC, Numeric, NVARCHAR, - PickleType, REAL, SchemaType, SMALLINT, SmallInteger, String, - STRINGTYPE, TEXT, Text, TIME, Time, TIMESTAMP, TupleType, - Unicode, UnicodeText, UUID, Uuid, VARBINARY, VARCHAR - ) - from sqlalchemy.sql.type_api import ( - adapt_type, ExternalType, to_instance, TypeDecorator, TypeEngine, - UserDefinedType, Variant - ) + from sqlalchemy.sql.sqltypes import ( + Integer, SmallInteger, BigInteger, String, Text, Unicode, UnicodeText, + Boolean, Date, Time, DateTime, Interval, + Float, Numeric, DECIMAL, + Enum, LargeBinary, JSON, PickleType, REAL, + CHAR, VARCHAR, NCHAR, NVARCHAR, BINARY, VARBINARY, + CLOB, BLOB, SchemaType, TupleType, UUID, Uuid, + ) + from sqlalchemy.sql.type_api import ( + TypeEngine, TypeDecorator, UserDefinedType, Variant, ExternalType, + ) + from sqlalchemy.sql.sqltypes import NullType +# SQLAlchemy >= 1.4 and < 2.0 +elif SA_VERSION_MM >= (1, 4): + from sqlalchemy.sql.sqltypes import ( + Integer, SmallInteger, BigInteger, String, Text, Unicode, UnicodeText, + Boolean, Date, Time, DateTime, Interval, + Float, Numeric, DECIMAL, + Enum, LargeBinary, JSON, PickleType, REAL, + CHAR, VARCHAR, NCHAR, NVARCHAR, + BINARY, VARBINARY, CLOB, BLOB, SchemaType, TupleType, + ) + from sqlalchemy.sql.type_api import ( + TypeEngine, TypeDecorator, UserDefinedType, Variant, ExternalType, + ) + from sqlalchemy.sql.sqltypes import NullType + UUID = None + Uuid = None +# SQLAlchemy <= 1.3 else: - from sqlalchemy.sql.sqltypes import NullType, NULLTYPE, _Binary - from sqlalchemy.sql.sqltypes import ( - ARRAY, BIGINT, BigInteger, BINARY, BLOB, BOOLEAN, Boolean, - CHAR, CLOB, Concatenable, DATE, Date, DATETIME, DateTime, - DECIMAL, Enum, FLOAT, Float, Indexable, INT, INTEGER, Integer, - Interval, JSON, LargeBinary, MatchType, NCHAR, - NUMERIC, Numeric, NVARCHAR, PickleType, REAL, - SchemaType, SMALLINT, SmallInteger, String, STRINGTYPE, TEXT, - Text, TIME, Time, TIMESTAMP, TupleType, Unicode, UnicodeText, - VARBINARY, VARCHAR - ) - from sqlalchemy.sql.type_api import ( - adapt_type, ExternalType, to_instance, TypeDecorator, TypeEngine, - UserDefinedType, Variant - ) + from sqlalchemy.sql.sqltypes import ( + Integer, SmallInteger, BigInteger, String, Text, Unicode, UnicodeText, + Boolean, Date, Time, DateTime, Interval, + Float, Numeric, DECIMAL, + Enum, LargeBinary, JSON, PickleType, REAL, + CHAR, VARCHAR, NCHAR, NVARCHAR, + BINARY, VARBINARY, CLOB, BLOB, SchemaType, + ) + from sqlalchemy.sql.type_api import ( + TypeEngine, TypeDecorator, UserDefinedType, Variant, + ) + from sqlalchemy.sql.sqltypes import NullType + # Not available in SQLAlchemy 1.3 + TupleType = None + ExternalType = None + UUID = None + Uuid = None + +# Stable aliases for internal use (all SA versions) +BOOLEAN = Boolean +INTEGER = Integer +SMALLINT = SmallInteger +BIGINT = BigInteger +NUMERIC = Numeric +FLOAT = Float +DATE = Date +TIME = Time +DATETIME = DateTime +TIMESTAMP = DateTime # as documented from: # http://publib.boulder.ibm.com/infocenter/db2luw/v9/index.jsp?topic=/com.ibm.db2.udb.doc/admin/r0001095.htm @@ -555,7 +584,7 @@ def visit_cast(self, cast, **kw): SMALLINT, SmallInteger, INTEGER, Integer, BIGINT, BigInteger, - DECIMAL, NUMERIC, Float, REAL, DOUBLE, Double, Numeric, + DECIMAL, NUMERIC, Float, REAL, DOUBLE, Numeric, DATE, Date, TIME, Time, TIMESTAMP, DateTime, BOOLEAN, Boolean, NullType