Skip to content

Commit b3ec076

Browse files
authored
Merge pull request #1745 from dbcli/RW/deprecate-dsn-environment-variable
Deprecate `DSN` environment variable in favor of `MYSQL_DSN`
2 parents 896c259 + ecd2613 commit b3ec076

3 files changed

Lines changed: 118 additions & 1 deletion

File tree

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Features
55
---------
66
* Respond to `-h` alone with the helpdoc.
77
* Allow `--hostname` as an alias for `--host`.
8+
* Deprecate `$DSN` environment variable in favor of `$MYSQL_DSN`.
89

910

1011
Bug Fixes

mycli/main.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2055,7 +2055,7 @@ class CliArgs:
20552055
'-d',
20562056
type=str,
20572057
default='',
2058-
envvar='DSN',
2058+
envvar='MYSQL_DSN',
20592059
help='DSN alias configured in the ~/.myclirc file, or a full DSN.',
20602060
)
20612061
list_dsn: bool = clickdc.option(
@@ -2344,6 +2344,16 @@ def get_password_from_file(password_file: str | None) -> str | None:
23442344
if not cli_args.socket:
23452345
cli_args.socket = os.environ['MYSQL_UNIX_PORT']
23462346

2347+
if 'DSN' in os.environ:
2348+
# deprecated 2026-03
2349+
click.secho(
2350+
"The DSN environment variable is deprecated in favor of MYSQL_DSN. Support for DSN will be removed in a future release.",
2351+
err=True,
2352+
fg="red",
2353+
)
2354+
if not cli_args.dsn:
2355+
cli_args.dsn = os.environ['DSN']
2356+
23472357
# Choose which ever one has a valid value.
23482358
database = cli_args.dbname or cli_args.database
23492359

test/pytests/test_main.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,112 @@ def run_query(self, query, new_line=True):
11181118
assert MockMyCli.connect_args['character_set'] == 'utf8mb3'
11191119

11201120

1121+
def test_mysql_dsn_envvar(monkeypatch):
1122+
class Formatter:
1123+
format_name = None
1124+
1125+
class Logger:
1126+
def debug(self, *args, **args_dict):
1127+
pass
1128+
1129+
def warning(self, *args, **args_dict):
1130+
pass
1131+
1132+
class MockMyCli:
1133+
config = {
1134+
'main': {},
1135+
'alias_dsn': {},
1136+
'connection': {
1137+
'default_keepalive_ticks': 0,
1138+
},
1139+
}
1140+
1141+
def __init__(self, **_args):
1142+
self.logger = Logger()
1143+
self.destructive_warning = False
1144+
self.main_formatter = Formatter()
1145+
self.redirect_formatter = Formatter()
1146+
self.ssl_mode = 'auto'
1147+
self.my_cnf = {'client': {}, 'mysqld': {}}
1148+
self.default_keepalive_ticks = 0
1149+
1150+
def connect(self, **args):
1151+
MockMyCli.connect_args = args
1152+
1153+
def run_query(self, query, new_line=True):
1154+
pass
1155+
1156+
import mycli.main
1157+
1158+
monkeypatch.setattr(mycli.main, 'MyCli', MockMyCli)
1159+
monkeypatch.setenv('MYSQL_DSN', 'mysql://dsn_user:dsn_passwd@dsn_host:7/dsn_database')
1160+
runner = CliRunner()
1161+
1162+
result = runner.invoke(mycli.main.click_entrypoint)
1163+
assert result.exit_code == 0, result.output + ' ' + str(result.exception)
1164+
assert 'DSN environment variable is deprecated' not in result.output
1165+
assert (
1166+
MockMyCli.connect_args['user'] == 'dsn_user'
1167+
and MockMyCli.connect_args['passwd'] == 'dsn_passwd'
1168+
and MockMyCli.connect_args['host'] == 'dsn_host'
1169+
and MockMyCli.connect_args['port'] == 7
1170+
and MockMyCli.connect_args['database'] == 'dsn_database'
1171+
)
1172+
1173+
1174+
def test_legacy_dsn_envvar_warns_and_falls_back(monkeypatch):
1175+
class Formatter:
1176+
format_name = None
1177+
1178+
class Logger:
1179+
def debug(self, *args, **args_dict):
1180+
pass
1181+
1182+
def warning(self, *args, **args_dict):
1183+
pass
1184+
1185+
class MockMyCli:
1186+
config = {
1187+
'main': {},
1188+
'alias_dsn': {},
1189+
'connection': {
1190+
'default_keepalive_ticks': 0,
1191+
},
1192+
}
1193+
1194+
def __init__(self, **_args):
1195+
self.logger = Logger()
1196+
self.destructive_warning = False
1197+
self.main_formatter = Formatter()
1198+
self.redirect_formatter = Formatter()
1199+
self.ssl_mode = 'auto'
1200+
self.my_cnf = {'client': {}, 'mysqld': {}}
1201+
self.default_keepalive_ticks = 0
1202+
1203+
def connect(self, **args):
1204+
MockMyCli.connect_args = args
1205+
1206+
def run_query(self, query, new_line=True):
1207+
pass
1208+
1209+
import mycli.main
1210+
1211+
monkeypatch.setattr(mycli.main, 'MyCli', MockMyCli)
1212+
monkeypatch.setenv('DSN', 'mysql://dsn_user:dsn_passwd@dsn_host:8/dsn_database')
1213+
runner = CliRunner()
1214+
1215+
result = runner.invoke(mycli.main.click_entrypoint)
1216+
assert result.exit_code == 0, result.output + ' ' + str(result.exception)
1217+
assert 'The DSN environment variable is deprecated' in result.output
1218+
assert (
1219+
MockMyCli.connect_args['user'] == 'dsn_user'
1220+
and MockMyCli.connect_args['passwd'] == 'dsn_passwd'
1221+
and MockMyCli.connect_args['host'] == 'dsn_host'
1222+
and MockMyCli.connect_args['port'] == 8
1223+
and MockMyCli.connect_args['database'] == 'dsn_database'
1224+
)
1225+
1226+
11211227
def test_password_flag_uses_sentinel(monkeypatch):
11221228
class Formatter:
11231229
format_name = None

0 commit comments

Comments
 (0)