Skip to content

Commit a0e6975

Browse files
committed
WL#16327: Remove Cursors Prepared Raw and Named Tuple
The cursors deprecated via WL#16318 are being removed in this worklog. Change-Id: Ic2eef8ecea6f8bb4c912b11998acbd525713a474
1 parent 68a6b51 commit a0e6975

22 files changed

+36
-1634
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Full release notes:
1111
v9.3.0
1212
======
1313

14+
- WL#16327: Remove Cursors Prepared Raw and Named Tuple
1415
- BUG#37453587: Github links in PyPI project's pages do not work
1516
- BUG#37418436: Arbitrary File Read in MySQL Python Client library
1617

mysql-connector-python/lib/mysql/connector/abstracts.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,6 @@
123123
)
124124
from .utils import GenericWrapper, import_object
125125

126-
NAMED_TUPLE_CACHE: weakref.WeakValueDictionary[Any, Any] = weakref.WeakValueDictionary()
127-
128126
DUPLICATED_IN_LIST_ERROR = (
129127
"The '{list}' list must not contain repeated values, the value "
130128
"'{value}' is duplicated."
@@ -1681,7 +1679,6 @@ def cursor(
16811679
prepared: Optional[bool] = None,
16821680
cursor_class: Optional[Type["MySQLCursorAbstract"]] = None,
16831681
dictionary: Optional[bool] = None,
1684-
named_tuple: Optional[bool] = None,
16851682
read_timeout: Optional[int] = None,
16861683
write_timeout: Optional[int] = None,
16871684
) -> "MySQLCursorAbstract":
@@ -1690,9 +1687,9 @@ def cursor(
16901687
By default, `MySQLCursor` or `CMySQLCursor` is returned. Depending on the
16911688
options while connecting, a buffered and/or raw cursor is instantiated
16921689
instead. Also depending upon the cursor options, rows can be returned as
1693-
dictionary or named tuple.
1690+
a dictionary or a tuple.
16941691
1695-
Dictionary and namedtuple based cursors are available with buffered output
1692+
Dictionary based cursors are available with buffered output
16961693
but not raw.
16971694
16981695
It is possible to also give a custom cursor through the `cursor_class`
@@ -1716,7 +1713,6 @@ def cursor(
17161713
or `cursor_cext.CMySQLCursor` according to the type of
17171714
connection that's being used.
17181715
dictionary: If `True`, the cursor returns rows as dictionaries.
1719-
named_tuple: If `True`, the cursor returns rows as named tuples.
17201716
read_timeout: A positive integer representing timeout in seconds for each
17211717
attempt to read any data from the server.
17221718
write_timeout: A positive integer representing timeout in seconds for each

mysql-connector-python/lib/mysql/connector/aio/abstracts.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@
118118

119119

120120
IS_POSIX = os.name == "posix"
121-
NAMED_TUPLE_CACHE: weakref.WeakValueDictionary[Any, Any] = weakref.WeakValueDictionary()
122121

123122

124123
@dataclass
@@ -1456,16 +1455,15 @@ async def cursor(
14561455
prepared: Optional[bool] = None,
14571456
cursor_class: Optional[Type[MySQLCursorAbstract]] = None,
14581457
dictionary: Optional[bool] = None,
1459-
named_tuple: Optional[bool] = None,
14601458
read_timeout: Optional[int] = None,
14611459
write_timeout: Optional[int] = None,
14621460
) -> MySQLCursorAbstract:
14631461
"""Instantiate and return a cursor.
14641462
14651463
By default, MySQLCursor is returned. Depending on the options while
14661464
connecting, a buffered and/or raw cursor is instantiated instead.
1467-
Also depending upon the cursor options, rows can be returned as dictionary or
1468-
named tuple.
1465+
Also depending upon the cursor options, rows can be returned as a dictionary
1466+
or a tuple.
14691467
14701468
It is possible to also give a custom cursor through the cursor_class
14711469
parameter, but it needs to be a subclass of

mysql-connector-python/lib/mysql/connector/aio/connection.py

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@
6767
ServerCmd,
6868
ServerFlag,
6969
flag_is_set,
70-
raise_warning_against_deprecated_cursor_class,
7170
)
7271
from ..errors import (
7372
ConnectionTimeoutError,
@@ -108,14 +107,10 @@
108107
MySQLCursor,
109108
MySQLCursorBuffered,
110109
MySQLCursorBufferedDict,
111-
MySQLCursorBufferedNamedTuple,
112110
MySQLCursorBufferedRaw,
113111
MySQLCursorDict,
114-
MySQLCursorNamedTuple,
115112
MySQLCursorPrepared,
116113
MySQLCursorPreparedDict,
117-
MySQLCursorPreparedNamedTuple,
118-
MySQLCursorPreparedRaw,
119114
MySQLCursorRaw,
120115
)
121116
from .logger import logger
@@ -787,16 +782,15 @@ async def cursor(
787782
prepared: Optional[bool] = None,
788783
cursor_class: Optional[Type[MySQLCursorAbstract]] = None,
789784
dictionary: Optional[bool] = None,
790-
named_tuple: Optional[bool] = None,
791785
read_timeout: Optional[int] = None,
792786
write_timeout: Optional[int] = None,
793787
) -> MySQLCursor:
794788
"""Instantiate and return a cursor.
795789
796790
By default, MySQLCursor is returned. Depending on the options while
797791
connecting, a buffered and/or raw cursor is instantiated instead.
798-
Also depending upon the cursor options, rows can be returned as dictionary or
799-
named tuple.
792+
Also depending upon the cursor options, rows can be returned as a dictionary
793+
or a tuple.
800794
801795
It is possible to also give a custom cursor through the cursor_class
802796
parameter, but it needs to be a subclass of
@@ -839,8 +833,6 @@ async def cursor(
839833
cursor_type |= 2
840834
if dictionary is True:
841835
cursor_type |= 4
842-
if named_tuple is True:
843-
cursor_type |= 8
844836
if prepared is True:
845837
cursor_type |= 16
846838

@@ -851,22 +843,15 @@ async def cursor(
851843
3: MySQLCursorBufferedRaw,
852844
4: MySQLCursorDict,
853845
5: MySQLCursorBufferedDict,
854-
8: MySQLCursorNamedTuple,
855-
9: MySQLCursorBufferedNamedTuple,
856846
16: MySQLCursorPrepared,
857-
18: MySQLCursorPreparedRaw,
858847
20: MySQLCursorPreparedDict,
859-
24: MySQLCursorPreparedNamedTuple,
860848
}
861849
try:
862-
raise_warning_against_deprecated_cursor_class(
863-
cursor_name=types[cursor_type].__name__
864-
)
865850
return (types[cursor_type])(self, read_timeout, write_timeout)
866851
except KeyError:
867-
args = ("buffered", "raw", "dictionary", "named_tuple", "prepared")
852+
args = ("buffered", "raw", "dictionary", "prepared")
868853
criteria = ", ".join(
869-
[args[i] for i in range(5) if cursor_type & (1 << i) != 0]
854+
[args[i] for i in range(4) if cursor_type & (1 << i) != 0]
870855
)
871856
raise ValueError(
872857
f"Cursor not available with given criteria: {criteria}"

mysql-connector-python/lib/mysql/connector/aio/cursor.py

Lines changed: 2 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2023, 2024, Oracle and/or its affiliates.
1+
# Copyright (c) 2023, 2025, Oracle and/or its affiliates.
22
#
33
# This program is free software; you can redistribute it and/or modify
44
# it under the terms of the GNU General Public License, version 2.0, as
@@ -35,7 +35,6 @@
3535
import re
3636
import warnings
3737

38-
from collections import namedtuple
3938
from decimal import Decimal
4039
from typing import (
4140
Any,
@@ -83,7 +82,7 @@
8382
StrOrBytes,
8483
WarningType,
8584
)
86-
from .abstracts import NAMED_TUPLE_CACHE, MySQLConnectionAbstract, MySQLCursorAbstract
85+
from .abstracts import MySQLConnectionAbstract, MySQLCursorAbstract
8786
from .utils import deprecated
8887

8988
ERR_NO_RESULT_TO_FETCH = "No result set to fetch from"
@@ -576,11 +575,6 @@ async def callproc(
576575
self._connection.can_consume_results = False
577576
if isinstance(self, (MySQLCursorDict, MySQLCursorBufferedDict)):
578577
cursor_class = MySQLCursorBufferedDict
579-
elif isinstance(
580-
self,
581-
(MySQLCursorNamedTuple, MySQLCursorBufferedNamedTuple),
582-
):
583-
cursor_class = MySQLCursorBufferedNamedTuple
584578
elif self._raw:
585579
cursor_class = MySQLCursorBufferedRaw
586580
else:
@@ -1005,64 +999,6 @@ async def fetchall(self) -> List[Optional[Dict[str, RowItemType]]]:
1005999
]
10061000

10071001

1008-
class MySQLCursorNamedTuple(MySQLCursor):
1009-
"""
1010-
Cursor fetching rows as named tuple.
1011-
1012-
The fetch methods of this class will return namedtuples instead of tuples.
1013-
Each row is returned as a namedtuple and the values can be accessed as:
1014-
row.col1, row.col2
1015-
"""
1016-
1017-
def _row_to_python(
1018-
self,
1019-
rowdata: RowType,
1020-
desc: Optional[List[DescriptionType]] = None, # pylint: disable=unused-argument
1021-
) -> Optional[RowType]:
1022-
"""Convert a MySQL text result row to Python types
1023-
1024-
Returns a named tuple.
1025-
"""
1026-
row = rowdata
1027-
1028-
if row:
1029-
columns = tuple(self.column_names)
1030-
try:
1031-
named_tuple = NAMED_TUPLE_CACHE[columns]
1032-
except KeyError:
1033-
named_tuple = namedtuple("Row", columns) # type:ignore[no-redef, misc]
1034-
NAMED_TUPLE_CACHE[columns] = named_tuple
1035-
return named_tuple(*row)
1036-
return None
1037-
1038-
async def fetchone(self) -> Optional[RowType]:
1039-
"""Return next row of a query result set.
1040-
1041-
Returns:
1042-
tuple or None: A row from query result set.
1043-
"""
1044-
row = await super().fetchone()
1045-
if not row:
1046-
return None
1047-
return (
1048-
self._row_to_python(row, self.description)
1049-
if hasattr(self._connection, "converter")
1050-
else row
1051-
)
1052-
1053-
async def fetchall(self) -> List[Optional[RowType]]:
1054-
"""Return all rows of a query result set.
1055-
1056-
Returns:
1057-
list: A list of tuples with all rows of a query result set.
1058-
"""
1059-
return [
1060-
self._row_to_python(row, self.description)
1061-
for row in await super().fetchall()
1062-
if row
1063-
]
1064-
1065-
10661002
class MySQLCursorBufferedDict(MySQLCursorDict, MySQLCursorBuffered):
10671003
"""
10681004
Buffered Cursor fetching rows as dictionaries.
@@ -1095,38 +1031,6 @@ async def fetchall(self) -> List[Optional[Dict[str, RowItemType]]]:
10951031
return res
10961032

10971033

1098-
class MySQLCursorBufferedNamedTuple(MySQLCursorNamedTuple, MySQLCursorBuffered):
1099-
"""
1100-
Buffered Cursor fetching rows as named tuple.
1101-
"""
1102-
1103-
async def fetchone(self) -> Optional[RowType]:
1104-
"""Return next row of a query result set.
1105-
1106-
Returns:
1107-
tuple or None: A row from query result set.
1108-
"""
1109-
self._check_executed()
1110-
row = await self._fetch_row()
1111-
if row:
1112-
return self._row_to_python(row, self.description)
1113-
return None
1114-
1115-
async def fetchall(self) -> List[Optional[RowType]]:
1116-
"""Return all rows of a query result set.
1117-
1118-
Returns:
1119-
list: A list of tuples with all rows of a query result set.
1120-
"""
1121-
if self._executed is None or self._rows is None:
1122-
raise InterfaceError(ERR_NO_RESULT_TO_FETCH)
1123-
res = []
1124-
for row in self._rows[self._next_row :]:
1125-
res.append(self._row_to_python(row, self.description))
1126-
self._next_row = len(self._rows)
1127-
return res
1128-
1129-
11301034
class MySQLCursorPrepared(MySQLCursor):
11311035
"""Cursor using MySQL Prepared Statements"""
11321036

@@ -1481,105 +1385,3 @@ async def fetchmany(
14811385
for row in await super().fetchmany(size=size)
14821386
if row
14831387
]
1484-
1485-
1486-
class MySQLCursorPreparedNamedTuple(MySQLCursorNamedTuple, MySQLCursorPrepared):
1487-
"""
1488-
This class is a blend of features from MySQLCursorNamedTuple and MySQLCursorPrepared
1489-
"""
1490-
1491-
async def fetchmany(self, size: Optional[int] = None) -> List[RowType]:
1492-
"""Return the next set of rows of a query result set.
1493-
1494-
When no more rows are available, it returns an empty list.
1495-
The number of rows returned can be specified using the size argument,
1496-
which defaults to one.
1497-
1498-
Returns:
1499-
list: The next set of rows of a query result set represented
1500-
as a list of named tuples where column names are used as names.
1501-
"""
1502-
return [
1503-
self._row_to_python(row, self.description)
1504-
for row in await super().fetchmany(size=size)
1505-
if row
1506-
]
1507-
1508-
1509-
class MySQLCursorPreparedRaw(MySQLCursorPrepared):
1510-
"""
1511-
This class is a blend of features from MySQLCursorRaw and MySQLCursorPrepared
1512-
"""
1513-
1514-
def __init__(
1515-
self,
1516-
connection: MySQLConnectionAbstract,
1517-
read_timeout: Optional[int] = None,
1518-
write_timeout: Optional[int] = None,
1519-
):
1520-
super().__init__(connection, read_timeout, write_timeout)
1521-
self._raw: bool = True
1522-
1523-
async def fetchone(self) -> Optional[RowType]:
1524-
"""Return next row of a query result set.
1525-
1526-
Returns:
1527-
tuple or None: A row from query result set.
1528-
"""
1529-
self._check_executed()
1530-
if self._cursor_exists:
1531-
await self._connection.cmd_stmt_fetch(
1532-
self._prepared["statement_id"],
1533-
read_timeout=self._read_timeout,
1534-
write_timeout=self._write_timeout,
1535-
)
1536-
return await self._fetch_row(raw=self._raw) or None
1537-
1538-
async def fetchmany(self, size: Optional[int] = None) -> List[RowType]:
1539-
"""Return the next set of rows of a query result set.
1540-
1541-
When no more rows are available, it returns an empty list.
1542-
The number of rows returned can be specified using the size argument,
1543-
which defaults to one.
1544-
1545-
Returns:
1546-
list: The next set of rows of a query result set.
1547-
"""
1548-
self._check_executed()
1549-
res = []
1550-
cnt = size or self.arraysize
1551-
while cnt > 0 and self._have_unread_result():
1552-
cnt -= 1
1553-
row = await self._fetch_row(raw=self._raw)
1554-
if row:
1555-
res.append(row)
1556-
return res
1557-
1558-
async def fetchall(self) -> List[RowType]:
1559-
"""Return all rows of a query result set.
1560-
1561-
Returns:
1562-
list: A list of tuples with all rows of a query result set.
1563-
"""
1564-
self._check_executed()
1565-
rows = []
1566-
if self._nextrow[0]:
1567-
rows.append(self._nextrow[0])
1568-
while self._have_unread_result():
1569-
if self._cursor_exists:
1570-
await self._connection.cmd_stmt_fetch(
1571-
self._prepared["statement_id"],
1572-
MAX_RESULTS,
1573-
read_timeout=self._read_timeout,
1574-
write_timeout=self._write_timeout,
1575-
)
1576-
tmp, eof = await self._connection.get_rows(
1577-
raw=self._raw,
1578-
binary=self._binary,
1579-
columns=self.description,
1580-
read_timeout=self._read_timeout,
1581-
)
1582-
rows.extend(tmp)
1583-
await self._handle_eof(eof)
1584-
self._rowcount = len(rows)
1585-
return rows

0 commit comments

Comments
 (0)