Skip to content

Commit e8b2445

Browse files
authored
fix: better handling for when c extension isn't available for mysql connector/python instead of erroring out (#1038)
1 parent 3b4d524 commit e8b2445

File tree

2 files changed

+41
-24
lines changed

2 files changed

+41
-24
lines changed

aws_advanced_python_wrapper/mysql_driver_dialect.py

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@
2323
from concurrent.futures import Executor, ThreadPoolExecutor, TimeoutError
2424
from inspect import signature
2525

26-
from mysql.connector import CMySQLConnection, MySQLConnection
27-
from mysql.connector.cursor import MySQLCursor
28-
from mysql.connector.cursor_cext import CMySQLCursor
29-
3026
from aws_advanced_python_wrapper.driver_dialect import DriverDialect
3127
from aws_advanced_python_wrapper.driver_dialect_codes import DriverDialectCodes
3228
from aws_advanced_python_wrapper.errors import UnsupportedOperationError
@@ -36,6 +32,21 @@
3632
PropertiesUtils,
3733
WrapperProperties)
3834

35+
CMYSQL_ENABLED = False
36+
37+
from mysql.connector import MySQLConnection # noqa: E402
38+
from mysql.connector.cursor import MySQLCursor # noqa: E402
39+
40+
try:
41+
from mysql.connector import CMySQLConnection # noqa: E402
42+
from mysql.connector.cursor_cext import CMySQLCursor # noqa: E402
43+
44+
CMYSQL_ENABLED = True
45+
46+
except ImportError:
47+
# Do nothing
48+
pass
49+
3950

4051
class MySQLDriverDialect(DriverDialect):
4152
_driver_name = "MySQL Connector Python"
@@ -62,20 +73,28 @@ class MySQLDriverDialect(DriverDialect):
6273
"Cursor.fetchall"
6374
}
6475

76+
@staticmethod
77+
def _is_mysql_connection(conn: Connection | object) -> bool:
78+
return isinstance(conn, MySQLConnection) or (CMYSQL_ENABLED and isinstance(conn, CMySQLConnection))
79+
80+
@staticmethod
81+
def _is_cmysql_cursor(obj: object) -> bool:
82+
return CMYSQL_ENABLED and isinstance(obj, CMySQLCursor)
83+
6584
def is_dialect(self, connect_func: Callable) -> bool:
6685
if MySQLDriverDialect.TARGET_DRIVER_CODE not in str(signature(connect_func)):
6786
return MySQLDriverDialect.TARGET_DRIVER_CODE.lower() in (connect_func.__module__ + connect_func.__qualname__).lower()
6887
return True
6988

7089
def is_closed(self, conn: Connection) -> bool:
71-
if isinstance(conn, CMySQLConnection) or isinstance(conn, MySQLConnection):
90+
if MySQLDriverDialect._is_mysql_connection(conn):
7291

7392
# is_connected validates the connection using a ping().
7493
# If there are any unread results from previous executions an error will be thrown.
7594
if self.can_execute_query(conn):
7695
socket_timeout = WrapperProperties.SOCKET_TIMEOUT_SEC.get_float(self._props)
7796
timeout_sec = socket_timeout if socket_timeout > 0 else MySQLDriverDialect.IS_CLOSED_TIMEOUT_SEC
78-
is_connected_with_timeout = timeout(MySQLDriverDialect._executor, timeout_sec)(conn.is_connected)
97+
is_connected_with_timeout = timeout(MySQLDriverDialect._executor, timeout_sec)(conn.is_connected) # type: ignore
7998

8099
try:
81100
return not is_connected_with_timeout()
@@ -86,15 +105,15 @@ def is_closed(self, conn: Connection) -> bool:
86105
raise UnsupportedOperationError(Messages.get_formatted("DriverDialect.UnsupportedOperationError", self._driver_name, "is_connected"))
87106

88107
def get_autocommit(self, conn: Connection) -> bool:
89-
if isinstance(conn, CMySQLConnection) or isinstance(conn, MySQLConnection):
90-
return conn.autocommit
108+
if MySQLDriverDialect._is_mysql_connection(conn):
109+
return conn.autocommit # type: ignore
91110

92111
raise UnsupportedOperationError(
93112
Messages.get_formatted("DriverDialect.UnsupportedOperationError", self._driver_name, "autocommit"))
94113

95114
def set_autocommit(self, conn: Connection, autocommit: bool):
96-
if isinstance(conn, CMySQLConnection) or isinstance(conn, MySQLConnection):
97-
conn.autocommit = autocommit
115+
if MySQLDriverDialect._is_mysql_connection(conn):
116+
conn.autocommit = autocommit # type: ignore
98117
return
99118

100119
raise UnsupportedOperationError(
@@ -112,24 +131,24 @@ def abort_connection(self, conn: Connection):
112131
"abort_connection"))
113132

114133
def can_execute_query(self, conn: Connection) -> bool:
115-
if isinstance(conn, CMySQLConnection) or isinstance(conn, MySQLConnection):
116-
if conn.unread_result:
117-
return conn.can_consume_results
134+
if MySQLDriverDialect._is_mysql_connection(conn):
135+
if conn.unread_result: # type: ignore
136+
return conn.can_consume_results # type: ignore
118137
return True
119138

120139
def is_in_transaction(self, conn: Connection) -> bool:
121-
if isinstance(conn, CMySQLConnection) or isinstance(conn, MySQLConnection):
122-
return bool(conn.in_transaction)
140+
if MySQLDriverDialect._is_mysql_connection(conn):
141+
return bool(conn.in_transaction) # type: ignore
123142

124143
raise UnsupportedOperationError(
125144
Messages.get_formatted("DriverDialect.UnsupportedOperationError", self._driver_name,
126145
"in_transaction"))
127146

128147
def get_connection_from_obj(self, obj: object) -> Any:
129-
if isinstance(obj, CMySQLConnection) or isinstance(obj, MySQLConnection):
148+
if MySQLDriverDialect._is_mysql_connection(obj):
130149
return obj
131150

132-
if isinstance(obj, CMySQLCursor):
151+
if MySQLDriverDialect._is_cmysql_cursor(obj):
133152
try:
134153
conn = None
135154

@@ -140,25 +159,24 @@ def get_connection_from_obj(self, obj: object) -> Any:
140159
if conn is None:
141160
return None
142161

143-
if isinstance(conn, CMySQLConnection) or isinstance(conn, MySQLConnection):
162+
if MySQLDriverDialect._is_mysql_connection(conn):
144163
return conn
145164

146165
except ReferenceError:
147166
return None
148167

149168
if isinstance(obj, MySQLCursor):
150169
try:
151-
if isinstance(obj._connection, CMySQLConnection) or isinstance(obj._connection, MySQLConnection):
170+
if MySQLDriverDialect._is_mysql_connection(obj._connection):
152171
return obj._connection
153172
except ReferenceError:
154173
return None
155174

156175
return None
157176

158177
def transfer_session_state(self, from_conn: Connection, to_conn: Connection):
159-
if (isinstance(from_conn, CMySQLConnection) or isinstance(from_conn, MySQLConnection)) and (
160-
isinstance(to_conn, CMySQLConnection) or isinstance(to_conn, MySQLConnection)):
161-
to_conn.autocommit = from_conn.autocommit
178+
if MySQLDriverDialect._is_mysql_connection(from_conn) and MySQLDriverDialect._is_mysql_connection(to_conn):
179+
to_conn.autocommit = from_conn.autocommit # type: ignore
162180

163181
def ping(self, conn: Connection) -> bool:
164182
return not self.is_closed(conn)

tests/integration/container/test_blue_green_deployment.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030

3131
import mysql.connector
3232
import psycopg
33-
from mysql.connector import CMySQLConnection, MySQLConnection
3433

3534
from aws_advanced_python_wrapper.mysql_driver_dialect import MySQLDriverDialect
3635
from aws_advanced_python_wrapper.pg_driver_dialect import PgDriverDialect
@@ -458,7 +457,7 @@ def close_connection(self, conn: Optional[Connection]):
458457
def is_closed(self, conn: Connection) -> bool:
459458
if isinstance(conn, psycopg.Connection):
460459
return self.pg_dialect.is_closed(conn)
461-
elif isinstance(conn, CMySQLConnection) or isinstance(conn, MySQLConnection):
460+
elif MySQLDriverDialect._is_mysql_connection(conn):
462461
return self.mysql_dialect.is_closed(conn)
463462
elif isinstance(conn, AwsWrapperConnection):
464463
return conn.is_closed

0 commit comments

Comments
 (0)