Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
Upcoming (TBD)
==============

Bug Fixes
--------
* Read and write the default `myclirc` as UTF-8, fixing a startup crash on non-UTF-8 locales such as Japanese Windows.


v2.30.1 (2026/10/24)
==============

Expand Down
1 change: 1 addition & 0 deletions mycli/AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ Contributors:
* Puneet Dixit
* Liu Zhenlong
* Chris Burr
* Wei-Lun Li


Created by:
Expand Down
6 changes: 3 additions & 3 deletions mycli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,20 +197,20 @@ def read_config_files(
def create_default_config(list_values: bool = True) -> ConfigObj:
import mycli

default_config_file = resources.files(mycli).joinpath("myclirc").open('r')
default_config_file = resources.files(mycli).joinpath("myclirc").open('r', encoding='utf8')
return read_config_file(default_config_file, list_values=list_values)


def write_default_config(destination: str, overwrite: bool = False) -> None:
import mycli

with resources.files(mycli).joinpath("myclirc").open('r') as f:
with resources.files(mycli).joinpath("myclirc").open('r', encoding='utf8') as f:
default_config = f.read()
destination = os.path.expanduser(destination)
if not overwrite and exists(destination):
return

with open(destination, "w") as f:
with open(destination, "w", encoding='utf8') as f:
f.write(default_config)


Expand Down
29 changes: 29 additions & 0 deletions mycli_test/pytests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import logging
import os
import struct
import subprocess
import sys
from tempfile import NamedTemporaryFile
from types import SimpleNamespace
Expand Down Expand Up @@ -435,6 +436,34 @@ def test_create_and_write_default_config(tmp_path) -> None:
assert '[main]' in destination.read_text(encoding='utf8')


def test_default_config_does_not_use_locale_encoding(tmp_path) -> None:
# The packaged myclirc is UTF-8 with non-ASCII text, so opening it with the
# locale encoding fails on non-UTF-8 locales such as cp932 (Japanese Windows).
script = '\n'.join((
'import sys',
'from mycli.config import create_default_config, write_default_config',
'create_default_config()',
'write_default_config(sys.argv[1])',
))
result = subprocess.run(
[
sys.executable,
'-X',
'warn_default_encoding',
'-W',
'error::EncodingWarning:mycli.config',
'-c',
script,
str(tmp_path / 'myclirc'),
],
capture_output=True,
encoding='utf8',
errors='replace',
)
assert result.returncode == 0, result.stderr
assert '[main]' in (tmp_path / 'myclirc').read_text(encoding='utf8')


def test_get_mylogin_cnf_path_returns_none_for_missing_file(monkeypatch, tmp_path) -> None:
monkeypatch.setenv('MYSQL_TEST_LOGIN_FILE', str(tmp_path / 'missing.mylogin.cnf'))

Expand Down
Loading