Skip to content

Commit ec430bf

Browse files
committed
WL#16752: Deprecate class methods to access instance data or to know instance internal state
Change-Id: I4293ddd909ad45c755f25845dbea0171b3139f79
1 parent 09db398 commit ec430bf

28 files changed

+560
-252
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#16752: Deprecate class methods to access instance data or to know instance internal state
1415
- WL#16327: Remove Cursors Prepared Raw and Named Tuple
1516
- BUG#37541353: (Contribution) Fix typing annotation of MySQLConnectionAbstract's close function
1617
- BUG#37453587: Github links in PyPI project's pages do not work

mysql-connector-python/examples/microseconds.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
# Copyright (c) 2009, 2024, Oracle and/or its affiliates.
4+
# Copyright (c) 2009, 2025, Oracle and/or its affiliates.
55
#
66
# This program is free software; you can redistribute it and/or modify
77
# it under the terms of the GNU General Public License, version 2.0, as
@@ -59,10 +59,10 @@
5959
def main(config):
6060
output = []
6161
cnx = mysql.connector.Connect(**config)
62-
if cnx.get_server_version() < (5, 6, 4):
62+
if cnx.server_version < (5, 6, 4):
6363
output.append(
6464
"MySQL {0} does not support fractional precision"
65-
" for timestamps.".format(cnx.get_server_info())
65+
" for timestamps.".format(cnx.server_info)
6666
)
6767
return output
6868
cursor = cnx.cursor()

mysql-connector-python/examples/mysql_warnings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
# Copyright (c) 2016, 2024, Oracle and/or its affiliates.
4+
# Copyright (c) 2016, 2025, Oracle and/or its affiliates.
55
#
66
# This program is free software; you can redistribute it and/or modify
77
# it under the terms of the GNU General Public License, version 2.0, as
@@ -52,7 +52,7 @@ def main(config):
5252
cursor.execute(STMT)
5353
cursor.fetchall()
5454

55-
warnings = cursor.fetchwarnings()
55+
warnings = cursor.warnings
5656
if warnings:
5757
for w in warnings:
5858
output.append("%d: %s" % (w[1], w[2]))

mysql-connector-python/examples/transaction.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
# Copyright (c) 2009, 2024, Oracle and/or its affiliates.
4+
# Copyright (c) 2009, 2025, Oracle and/or its affiliates.
55
#
66
# This program is free software; you can redistribute it and/or modify
77
# it under the terms of the GNU General Public License, version 2.0, as
@@ -59,7 +59,7 @@ def main(config):
5959
) ENGINE=InnoDB"""
6060
cursor.execute(stmt_create)
6161

62-
warnings = cursor.fetchwarnings()
62+
warnings = cursor.warnings
6363
if warnings:
6464
ids = [i for l, i, m in warnings]
6565
output.append("Oh oh.. we got warnings..")

mysql-connector-python/examples/warnings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
# Copyright (c) 2009, 2024, Oracle and/or its affiliates.
4+
# Copyright (c) 2009, 2025, Oracle and/or its affiliates.
55
#
66
# This program is free software; you can redistribute it and/or modify
77
# it under the terms of the GNU General Public License, version 2.0, as
@@ -55,7 +55,7 @@ def main(config):
5555
cursor.execute(STMT)
5656
cursor.fetchall()
5757

58-
warnings = cursor.fetchwarnings()
58+
warnings = cursor.warnings
5959
if warnings:
6060
for w in warnings:
6161
output.append("%d: %s" % (w[1], w[2]))

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

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def wrapper(
4949
cnx: "MySQLConnectionAbstract", *args: Any, **kwargs: Any
5050
) -> Callable:
5151
options: int = args[0]
52-
if (options & RefreshOption.GRANT) and cnx.get_server_version() >= (
52+
if (options & RefreshOption.GRANT) and cnx.server_version >= (
5353
9,
5454
2,
5555
0,
@@ -68,3 +68,44 @@ def wrapper(
6868
return wrapper
6969

7070
return decorator
71+
72+
73+
def handle_read_write_timeout() -> Callable:
74+
"""
75+
Decorator to close the current connection if a read or a write timeout
76+
is raised by the method passed via the func parameter.
77+
"""
78+
79+
def decorator(cnx_method: Callable) -> Callable:
80+
@functools.wraps(cnx_method)
81+
def handle_cnx_method(
82+
cnx: "MySQLConnectionAbstract", *args: Any, **kwargs: Any
83+
) -> Any:
84+
try:
85+
return cnx_method(cnx, *args, **kwargs)
86+
except Exception as err:
87+
if isinstance(err, TimeoutError):
88+
cnx.close()
89+
raise err
90+
91+
return handle_cnx_method
92+
93+
return decorator
94+
95+
96+
def deprecated(reason: str) -> Callable:
97+
"""Use it to decorate deprecated methods."""
98+
99+
def decorator(func: Callable) -> Callable:
100+
@functools.wraps(func)
101+
def wrapper(*args: Any, **kwargs: Any) -> Callable:
102+
warnings.warn(
103+
f"Call to deprecated function {func.__name__}. Reason: {reason}",
104+
category=DeprecationWarning,
105+
stacklevel=2,
106+
)
107+
return func(*args, **kwargs)
108+
109+
return wrapper
110+
111+
return decorator

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

Lines changed: 101 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
from .constants import (
7676
CONN_ATTRS_DN,
7777
DEFAULT_CONFIGURATION,
78+
DEPRECATED_METHOD_WARNING,
7879
MYSQL_DEFAULT_CHARSET_ID_57,
7980
MYSQL_DEFAULT_CHARSET_ID_80,
8081
OPENSSL_CS_NAMES,
@@ -107,6 +108,7 @@
107108
trace,
108109
)
109110

111+
from ._decorating import deprecated
110112
from .optionfiles import read_option_files
111113
from .tls_ciphers import UNACCEPTABLE_TLS_CIPHERSUITES, UNACCEPTABLE_TLS_VERSIONS
112114
from .types import (
@@ -597,15 +599,15 @@ def config(self, **kwargs: Any) -> None:
597599
# Configure client flags
598600
try:
599601
default = ClientFlag.get_default()
600-
self.set_client_flags(config["client_flags"] or default)
602+
self.client_flags = config["client_flags"] or default
601603
del config["client_flags"]
602604
except KeyError:
603605
pass # Missing client_flags-argument is OK
604606

605607
try:
606608
if config["compress"]:
607609
self._compress = True
608-
self.set_client_flags([ClientFlag.COMPRESS])
610+
self.client_flags = [ClientFlag.COMPRESS]
609611
except KeyError:
610612
pass # Missing compress argument is OK
611613

@@ -627,9 +629,9 @@ def config(self, **kwargs: Any) -> None:
627629
):
628630
raise AttributeError("allow_local_infile_in_path must be a directory")
629631
if self._allow_local_infile or self._allow_local_infile_in_path:
630-
self.set_client_flags([ClientFlag.LOCAL_FILES])
632+
self.client_flags = [ClientFlag.LOCAL_FILES]
631633
else:
632-
self.set_client_flags([-ClientFlag.LOCAL_FILES])
634+
self.client_flags = [-ClientFlag.LOCAL_FILES]
633635

634636
try:
635637
if not config["consume_results"]:
@@ -655,7 +657,7 @@ def config(self, **kwargs: Any) -> None:
655657

656658
# Set converter class
657659
try:
658-
self.set_converter_class(config["converter_class"])
660+
self.converter_class = config["converter_class"]
659661
except KeyError:
660662
pass # Using default converter class
661663
except TypeError as err:
@@ -949,6 +951,7 @@ def _check_server_version(server_version: StrOrBytes) -> Tuple[int, ...]:
949951

950952
return version
951953

954+
@deprecated(DEPRECATED_METHOD_WARNING.format(property_name="server_version"))
952955
def get_server_version(self) -> Optional[Tuple[int, ...]]:
953956
"""Gets the MySQL version.
954957
@@ -958,9 +961,30 @@ def get_server_version(self) -> Optional[Tuple[int, ...]]:
958961
"""
959962
return self._server_version
960963

964+
@deprecated(DEPRECATED_METHOD_WARNING.format(property_name="server_info"))
961965
def get_server_info(self) -> Optional[str]:
962966
"""Gets the original MySQL version information.
963967
968+
Returns:
969+
The original MySQL server as text. If not previously connected, it will
970+
return `None`.
971+
"""
972+
return self.server_info
973+
974+
@property
975+
def server_version(self) -> Optional[Tuple[int, ...]]:
976+
"""Gets the MySQL Server version the connector is connected to.
977+
978+
Returns:
979+
The MySQL server version as a tuple. If not previously connected, it will
980+
return `None`.
981+
"""
982+
return self._server_version
983+
984+
@property
985+
def server_info(self) -> Optional[str]:
986+
"""Gets the original MySQL server version information.
987+
964988
Returns:
965989
The original MySQL server as text. If not previously connected, it will
966990
return `None`.
@@ -992,6 +1016,7 @@ def in_transaction(self) -> bool:
9921016
```
9931017
"""
9941018

1019+
@deprecated(DEPRECATED_METHOD_WARNING.format(property_name="client_flags"))
9951020
def set_client_flags(self, flags: Union[int, Sequence[int]]) -> int:
9961021
"""Sets the client flags.
9971022
@@ -1020,6 +1045,40 @@ def set_client_flags(self, flags: Union[int, Sequence[int]]) -> int:
10201045
>>> cnx.reconnect()
10211046
```
10221047
"""
1048+
self.client_flags = flags
1049+
return self.client_flags
1050+
1051+
@property
1052+
def client_flags(self) -> int:
1053+
"""Gets the client flags of the current session."""
1054+
return self._client_flags
1055+
1056+
@client_flags.setter
1057+
def client_flags(self, flags: Union[int, Sequence[int]]) -> None:
1058+
"""Sets the client flags.
1059+
1060+
The flags-argument can be either an int or a list (or tuple) of
1061+
ClientFlag-values. If it is an integer, it will set client_flags
1062+
to flags as is.
1063+
1064+
If flags is a sequence, each item in the sequence sets the flag when the
1065+
value is positive or unsets it when negative (see example below).
1066+
1067+
Args:
1068+
flags: A list (or tuple), each flag will be set or unset when it's negative.
1069+
1070+
Raises:
1071+
ProgrammingError: When the flags argument is not a set or an integer
1072+
bigger than 0.
1073+
1074+
Examples:
1075+
```
1076+
For example, to unset `LONG_FLAG` and set the `FOUND_ROWS` flags:
1077+
>>> from mysql.connector.constants import ClientFlag
1078+
>>> cnx.client_flags = [ClientFlag.FOUND_ROWS, -ClientFlag.LONG_FLAG]
1079+
>>> cnx.reconnect()
1080+
```
1081+
"""
10231082
if isinstance(flags, int) and flags > 0:
10241083
self._client_flags = flags
10251084
elif isinstance(flags, (tuple, list)):
@@ -1029,8 +1088,7 @@ def set_client_flags(self, flags: Union[int, Sequence[int]]) -> int:
10291088
else:
10301089
self._client_flags |= flag
10311090
else:
1032-
raise ProgrammingError("set_client_flags expect integer (>0) or set")
1033-
return self._client_flags
1091+
raise ProgrammingError("client_flags setter expect integer (>0) or set")
10341092

10351093
def shutdown(self) -> NoReturn:
10361094
"""Shuts down connection to MySQL Server.
@@ -1129,17 +1187,28 @@ def set_login(
11291187
else:
11301188
self._password = ""
11311189

1190+
@deprecated(DEPRECATED_METHOD_WARNING.format(property_name="use_unicode"))
11321191
def set_unicode(self, value: bool = True) -> None:
1133-
"""Toggles unicode mode.
1192+
"""Sets whether we return string fields as unicode or not.
1193+
1194+
Args:
1195+
value: A boolean - default is `True`.
1196+
"""
1197+
self.use_unicode = value
1198+
1199+
@property
1200+
def use_unicode(self) -> bool:
1201+
"""Gets whether we return string fields as unicode or not."""
1202+
return self._use_unicode
11341203

1135-
Sets whether we return string fields as unicode or not.
1204+
@use_unicode.setter
1205+
@abstractmethod
1206+
def use_unicode(self, value: bool) -> None:
1207+
"""Sets whether we return string fields as unicode or not.
11361208
11371209
Args:
11381210
value: A boolean - default is `True`.
11391211
"""
1140-
self._use_unicode = value
1141-
if self.converter:
1142-
self.converter.set_unicode(value)
11431212

11441213
@property
11451214
def autocommit(self) -> bool:
@@ -1882,18 +1951,35 @@ def reset_session(
18821951
cur.execute(f"SET SESSION `{key}` = {value}")
18831952
cur.close()
18841953

1954+
@deprecated(DEPRECATED_METHOD_WARNING.format(property_name="converter_class"))
18851955
def set_converter_class(self, convclass: Optional[Type[MySQLConverter]]) -> None:
18861956
"""
18871957
Sets the converter class to be used.
18881958
1959+
Args:
1960+
convclass: Should be a class overloading methods and members of
1961+
`conversion.MySQLConverter`.
1962+
"""
1963+
self.converter_class = convclass
1964+
1965+
@property
1966+
def converter_class(self) -> Optional[Type[MySQLConverter]]:
1967+
"""Gets the converter class set for the current session."""
1968+
return self._converter_class
1969+
1970+
@converter_class.setter
1971+
def converter_class(self, convclass: Optional[Type[MySQLConverter]]) -> None:
1972+
"""
1973+
Sets the converter class to be used.
1974+
18891975
Args:
18901976
convclass: Should be a class overloading methods and members of
18911977
`conversion.MySQLConverter`.
18921978
"""
18931979
if convclass and issubclass(convclass, MySQLConverterBase):
18941980
charset_name = self._character_set.get_info(self._charset_id)[0]
18951981
self._converter_class = convclass
1896-
self.converter = convclass(charset_name, self._use_unicode)
1982+
self.converter = convclass(charset_name, self.use_unicode)
18971983
self.converter.str_fallback = self._converter_str_fallback
18981984
else:
18991985
raise TypeError(
@@ -3010,7 +3096,7 @@ def lastrowid(self) -> Optional[int]:
30103096

30113097
@property
30123098
def warnings(self) -> Optional[List[WarningType]]:
3013-
"""Returns a list of tuples (WarningType) containing warnings generated
3099+
"""Gets a list of tuples (WarningType) containing warnings generated
30143100
by the previously executed operation.
30153101
30163102
Examples:
@@ -3053,6 +3139,7 @@ def statement(self) -> Optional[str]:
30533139
except (AttributeError, UnicodeDecodeError):
30543140
return cast(str, self._executed.strip())
30553141

3142+
@deprecated(DEPRECATED_METHOD_WARNING.format(property_name="warnings"))
30563143
def fetchwarnings(self) -> Optional[List[WarningType]]:
30573144
"""Returns a list of tuples (WarningType) containing warnings generated by
30583145
the previously executed operation.

0 commit comments

Comments
 (0)