Hello!
Running python3.8, mysql-connector-python 8.3.0, and mysql 8.0.35, I've run into something that I'm unsure qualifies as a bug, but at the very least I find strange behavior.
I've got some typical factory code that has 2 exactly-as-you'd-expect context-manager functions, one yields a database connection and the other uses that function to yield a cursor (for context for the next part).
-----
class DBConnectionFactory:
host: str
port: int
db: str
user: str
password: str
@contextlib.contextmanager
def connect(self) -> Iterator[mysql.MySQLConnection]:
conn = mysql.connect(
host=self.host,
port=self.port,
db=self.db,
user=self.user,
password=self.password,
)
conn.get_warnings = True
try:
yield conn
finally:
conn.close()
@contextlib.contextmanager
def cursor(self, dictionary: bool = False) -> Iterator[Cursor]:
with self.connect() as conn:
cur = conn.cursor(dictionary=dictionary)
try:
yield cur
finally:
cur.close()
-----
Attempting to run a PURGE BINARY LOGS command only works when run via the database connection:
-----
with db.connect() as conn:
conn.cmd_query(f"PURGE BINARY LOGS BEFORE '{start_time}';")
-----
Now, this is basically what the documentation dictates, but for the longest time, I was running it like this
-----
with db.cursor() as cur:
cur.execute(f"PURGE BINARY LOGS BEFORE '{start_time}';")
-----
because I did not understand that there was a difference at first. The "bug" behavior comes in with how mysql connector handles the response from the server. The purge command itself is run, I can validate it by listing the binary log files and asking mysql to SHOW BINARY LOGS. but the error comes in the stack trace.
-----
Traceback (most recent call last):
File "script.py", line 193, in flush_logs
cur.execute(f"PURGE BINARY LOGS BEFORE '{start_time}';")
File "venv/lib/python3.8/site-packages/mysql/connector/cursor.py", line 748, in execute
self._handle_result(self._connection.cmd_query(stmt))
File "/venv/lib/python3.8/site-packages/mysql/connector/cursor.py", line 614, in _handle_result
self._handle_noresultset(result)
File "/venv/lib/python3.8/site-packages/mysql/connector/cursor.py", line 585, in _handle_noresultset
self._handle_warnings()
File "/venv/lib/python3.8/site-packages/mysql/connector/cursor.py", line 1054, in _handle_warnings
warnings.warn(err, stacklevel=4)
TypeError: expected string or bytes-like object
-----
Best as I can tell, the warning handler for the cursor isn't prepared to handle the non-row response from the server. I confirmed that start_time was in fact a string, as well as the entire string I was passing to execute, so I looked into the source code and confirmed it was being thrown by the library.
Now, I'm not entirely sure what the best approach to this is. I'm unsure if it qualifies as a bug since I'm a) probably not supposed to be running the "Database level commands" like purge through execute and b) fully aware of the existence of cmd_query now
However, it seems like the library should either a) handle the error in a more pythonic manner since both approaches to actually run the command b) not let me run the command via execute or c) not throw an error at all.
I also verified that this error is only occurring after 8.0.12, as it doesn't throw an error at all with that version, but all subsequent versions throw the error. I'd be happy to file a bug request if this is considered a bug, but I figured I'd check in the forums before doing anything.
Running python3.8, mysql-connector-python 8.3.0, and mysql 8.0.35, I've run into something that I'm unsure qualifies as a bug, but at the very least I find strange behavior.
I've got some typical factory code that has 2 exactly-as-you'd-expect context-manager functions, one yields a database connection and the other uses that function to yield a cursor (for context for the next part).
-----
class DBConnectionFactory:
host: str
port: int
db: str
user: str
password: str
@contextlib.contextmanager
def connect(self) -> Iterator[mysql.MySQLConnection]:
conn = mysql.connect(
host=self.host,
port=self.port,
db=self.db,
user=self.user,
password=self.password,
)
conn.get_warnings = True
try:
yield conn
finally:
conn.close()
@contextlib.contextmanager
def cursor(self, dictionary: bool = False) -> Iterator[Cursor]:
with self.connect() as conn:
cur = conn.cursor(dictionary=dictionary)
try:
yield cur
finally:
cur.close()
-----
Attempting to run a PURGE BINARY LOGS command only works when run via the database connection:
-----
with db.connect() as conn:
conn.cmd_query(f"PURGE BINARY LOGS BEFORE '{start_time}';")
-----
Now, this is basically what the documentation dictates, but for the longest time, I was running it like this
-----
with db.cursor() as cur:
cur.execute(f"PURGE BINARY LOGS BEFORE '{start_time}';")
-----
because I did not understand that there was a difference at first. The "bug" behavior comes in with how mysql connector handles the response from the server. The purge command itself is run, I can validate it by listing the binary log files and asking mysql to SHOW BINARY LOGS. but the error comes in the stack trace.
-----
Traceback (most recent call last):
File "script.py", line 193, in flush_logs
cur.execute(f"PURGE BINARY LOGS BEFORE '{start_time}';")
File "venv/lib/python3.8/site-packages/mysql/connector/cursor.py", line 748, in execute
self._handle_result(self._connection.cmd_query(stmt))
File "/venv/lib/python3.8/site-packages/mysql/connector/cursor.py", line 614, in _handle_result
self._handle_noresultset(result)
File "/venv/lib/python3.8/site-packages/mysql/connector/cursor.py", line 585, in _handle_noresultset
self._handle_warnings()
File "/venv/lib/python3.8/site-packages/mysql/connector/cursor.py", line 1054, in _handle_warnings
warnings.warn(err, stacklevel=4)
TypeError: expected string or bytes-like object
-----
Best as I can tell, the warning handler for the cursor isn't prepared to handle the non-row response from the server. I confirmed that start_time was in fact a string, as well as the entire string I was passing to execute, so I looked into the source code and confirmed it was being thrown by the library.
Now, I'm not entirely sure what the best approach to this is. I'm unsure if it qualifies as a bug since I'm a) probably not supposed to be running the "Database level commands" like purge through execute and b) fully aware of the existence of cmd_query now
However, it seems like the library should either a) handle the error in a more pythonic manner since both approaches to actually run the command b) not let me run the command via execute or c) not throw an error at all.
I also verified that this error is only occurring after 8.0.12, as it doesn't throw an error at all with that version, but all subsequent versions throw the error. I'd be happy to file a bug request if this is considered a bug, but I figured I'd check in the forums before doing anything.