Skip to content

Commit f8b4d65

Browse files
committed
Fixed platform-dependent encoding.
- Added `encoding="utf-8"` to all writes.
1 parent 455c9bc commit f8b4d65

14 files changed

+72
-59
lines changed

bumpversion/cli.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ def sample_config(prompt: bool, destination: str) -> None:
548548
if destination == "stdout":
549549
print_info(dumps(destination_config))
550550
else:
551-
Path(destination).write_text(dumps(destination_config))
551+
Path(destination).write_text(dumps(destination_config), encoding="utf-8")
552552

553553

554554
@cli.command()

bumpversion/config/files_legacy.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,4 @@ def update_ini_config_file(
132132
)
133133

134134
if not dry_run:
135-
config_path.write_text(new_config)
135+
config_path.write_text(new_config, encoding="utf-8")

bumpversion/files.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -359,4 +359,4 @@ def _update_toml_file(
359359

360360
set_nested_value(toml_data, new_value, self.file_change.key_path)
361361

362-
self.path.write_text(tomlkit.dumps(toml_data))
362+
self.path.write_text(tomlkit.dumps(toml_data), encoding="utf-8")

tests/test_bump.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ def test_key_path_required_for_toml_change(tmp_path: Path, caplog):
217217
bake_cookies = true
218218
ignore-words-list = "sugar, salt, flour"
219219
"""
220-
)
220+
),
221+
encoding="utf-8",
221222
)
222223

223224
conf = config.get_configuration(config_file=config_path)

tests/test_cli/test_bump.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ def test_bump_nested_regex(tmp_path: Path, fixtures_path: Path, caplog, runner):
6464
Assert: There is no configured files specified to modify
6565
"""
6666
cff_path = tmp_path / "citation.cff"
67-
cff_path.write_text("cff-version: 1.2.0\ndate-released: 2023-09-19\n")
67+
cff_path.write_text("cff-version: 1.2.0\ndate-released: 2023-09-19\n", encoding="utf-8")
6868
content = fixtures_path.joinpath("regex_test_config.toml").read_text()
6969
config_path = tmp_path / ".bumpversion.toml"
70-
config_path.write_text(content)
70+
config_path.write_text(content, encoding="utf-8")
7171

7272
with inside_dir(tmp_path):
7373
result: Result = runner.invoke(cli.cli, ["bump", "-vv", "patch"])
@@ -162,7 +162,7 @@ def test_dirty_work_dir_raises_error(repo: str, scm_command: str, request, runne
162162
repo_path: Path = request.getfixturevalue(repo)
163163
with inside_dir(repo_path):
164164
# Arrange
165-
repo_path.joinpath("dirty2").write_text("i'm dirty! 1.1.1")
165+
repo_path.joinpath("dirty2").write_text("i'm dirty! 1.1.1", encoding="utf-8")
166166
subprocess.run([scm_command, "add", "dirty2"], check=True)
167167

168168
# Act
@@ -182,7 +182,7 @@ def test_non_scm_operations_if_scm_not_installed(tmp_path: Path, monkeypatch, ru
182182

183183
with inside_dir(tmp_path):
184184
version_path = tmp_path / "VERSION"
185-
version_path.write_text("31.0.3")
185+
version_path.write_text("31.0.3", encoding="utf-8")
186186

187187
# Act
188188
runner.invoke(cli.cli, ["bump", "major", "--current-version", "31.0.3", "VERSION"])
@@ -205,7 +205,7 @@ def test_detects_bad_or_missing_version_part(version_part: str, tmp_path: Path,
205205

206206
with inside_dir(tmp_path):
207207
version_path = tmp_path / "VERSION"
208-
version_path.write_text("31.0.3")
208+
version_path.write_text("31.0.3", encoding="utf-8")
209209

210210
args = ["bump", "--current-version", "31.0.3"]
211211
if version_part:
@@ -229,7 +229,8 @@ def test_ignores_missing_files_with_option(tmp_path, fixtures_path, runner):
229229
"allow_dirty = true\n\n"
230230
"[[tool.bumpversion.files]]\n"
231231
'filename = "VERSION"\n'
232-
"regex = false\n"
232+
"regex = false\n",
233+
encoding="utf-8",
233234
)
234235

235236
# Act

tests/test_cli/test_replace.py

+16-9
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ def test_ignores_missing_files_with_option(self, mocker, tmp_path, fixtures_path
122122
"allow_dirty = true\n\n"
123123
"[[tool.bumpversion.files]]\n"
124124
'filename = "VERSION"\n'
125-
"regex = false\n"
125+
"regex = false\n",
126+
encoding="utf-8",
126127
)
127128

128129
# Act
@@ -156,9 +157,11 @@ def test_accepts_plain_string(self, tmp_path, fixtures_path, runner):
156157

157158
# Arrange
158159
config_path = tmp_path / "pyproject.toml"
159-
config_path.write_text(dumps(TEST_REPLACE_CONFIG))
160+
config_path.write_text(dumps(TEST_REPLACE_CONFIG), encoding="utf-8")
160161
doc_path = tmp_path / "docs.yaml"
161-
doc_path.write_text("url: https://github.com/sampleuser/workflows/main/.github/update_mailmap.py")
162+
doc_path.write_text(
163+
"url: https://github.com/sampleuser/workflows/main/.github/update_mailmap.py", encoding="utf-8"
164+
)
162165

163166
with inside_dir(tmp_path):
164167
result: Result = runner.invoke(
@@ -189,7 +192,8 @@ def test_unintentional_valid_regex_still_found(self, tmp_path: Path, caplog, run
189192

190193
version_path = tmp_path / "VERSION"
191194
version_path.write_text(
192-
"# Changelog\n\n## [0.0.1 (unreleased)](https://cool.url)\n\n- Test unreleased package.\n"
195+
"# Changelog\n\n## [0.0.1 (unreleased)](https://cool.url)\n\n- Test unreleased package.\n",
196+
encoding="utf-8",
193197
)
194198
config_file = tmp_path / ".bumpversion.toml"
195199
config_file.write_text(
@@ -200,7 +204,8 @@ def test_unintentional_valid_regex_still_found(self, tmp_path: Path, caplog, run
200204
'filename = "VERSION"\n'
201205
"regex = false\n"
202206
f'search = "{search}"\n'
203-
f'replace = "{replace}"\n'
207+
f'replace = "{replace}"\n',
208+
encoding="utf-8",
204209
)
205210

206211
# Act
@@ -241,9 +246,9 @@ def test_accepts_empty_string(self, tmp_path, fixtures_path, runner):
241246

242247
# Arrange
243248
config_path = tmp_path / "pyproject.toml"
244-
config_path.write_text(dumps(TEST_REPLACE_CONFIG))
249+
config_path.write_text(dumps(TEST_REPLACE_CONFIG), encoding="utf-8")
245250
doc_path = tmp_path / "docs.yaml"
246-
doc_path.write_text("We should censor profanity\n\n")
251+
doc_path.write_text("We should censor profanity\n\n", encoding="utf-8")
247252

248253
with inside_dir(tmp_path):
249254
result: Result = runner.invoke(
@@ -274,9 +279,11 @@ def test_accepts_plain_string(self, tmp_path, fixtures_path, runner):
274279

275280
# Arrange
276281
config_path = tmp_path / "pyproject.toml"
277-
config_path.write_text(dumps(TEST_REPLACE_CONFIG))
282+
config_path.write_text(dumps(TEST_REPLACE_CONFIG), encoding="utf-8")
278283
doc_path = tmp_path / "docs.yaml"
279-
doc_path.write_text("url: https://github.com/sampleuser/workflows/v2.17.7/.github/update_mailmap.py")
284+
doc_path.write_text(
285+
"url: https://github.com/sampleuser/workflows/v2.17.7/.github/update_mailmap.py", encoding="utf-8"
286+
)
280287

281288
with inside_dir(tmp_path):
282289
result: Result = runner.invoke(

tests/test_config/test_create.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class TestGetDefaultsFromDest:
5050
def test_existing_path_returns_existing_config(self, tmp_path: Path, default_config: dict):
5151
"""If the destination exists, the existing config should be returned."""
5252
dest_path = tmp_path / "pyproject-1.toml"
53-
dest_path.write_text(dumps(BASIC_CONFIG))
53+
dest_path.write_text(dumps(BASIC_CONFIG), encoding="utf-8")
5454

5555
with inside_dir(tmp_path):
5656
config, destination_config = get_defaults_from_dest("pyproject-1.toml")
@@ -73,7 +73,7 @@ def test_missing_path_returns_default_config(self, tmp_path: Path, default_confi
7373
def test_existing_path_with_no_config_returns_default_config(self, tmp_path: Path, default_config: dict):
7474
"""If the destination exists but has no config, the default config should be returned."""
7575
dest_path = tmp_path / "pyproject-3.toml"
76-
dest_path.write_text(dumps({"tool": {"poetry": {}}}))
76+
dest_path.write_text(dumps({"tool": {"poetry": {}}}), encoding="utf-8")
7777

7878
with inside_dir(tmp_path):
7979
config, destination_config = get_defaults_from_dest("pyproject-3.toml")
@@ -85,7 +85,7 @@ def test_existing_path_with_no_config_returns_default_config(self, tmp_path: Pat
8585
def test_existing_path_with_project_version_uses_project_version(self, tmp_path: Path, default_config: dict):
8686
"""If the destination exists and has a project version, the project version should be used as current_version."""
8787
dest_path = tmp_path / "pyproject-4.toml"
88-
dest_path.write_text(dumps({"tool": {"poetry": {}}, "project": {"version": "1.2.3"}}))
88+
dest_path.write_text(dumps({"tool": {"poetry": {}}, "project": {"version": "1.2.3"}}), encoding="utf-8")
8989

9090
with inside_dir(tmp_path):
9191
config, destination_config = get_defaults_from_dest("pyproject-4.toml")

tests/test_config/test_files.py

+12-11
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class TestWhenExplictConfigFileIsPassed:
2525
def test_returns_path_to_existing_file(self, tmp_path: Path) -> None:
2626
"""If an explicit config file is passed, it should be returned."""
2727
cfg_file = tmp_path / "bump.toml"
28-
cfg_file.write_text('[tool.bumpversion]\ncurrent_version = "1.0.0"')
28+
cfg_file.write_text('[tool.bumpversion]\ncurrent_version = "1.0.0"', encoding="utf-8")
2929
assert find_config_file(cfg_file) == cfg_file
3030

3131
def test_returns_none_when_missing_file(self, tmp_path: Path) -> None:
@@ -43,7 +43,7 @@ class TestWhenNoExplicitConfigFileIsPassed:
4343
def test_returns_path_to_existing_default_file(self, tmp_path: Path, cfg_file_name: str) -> None:
4444
"""If no explicit config file is passed, it returns the path to an existing expected file."""
4545
cfg_file = tmp_path / cfg_file_name
46-
cfg_file.write_text('[tool.bumpversion]\ncurrent_version = "1.0.0"')
46+
cfg_file.write_text('[tool.bumpversion]\ncurrent_version = "1.0.0"', encoding="utf-8")
4747
with inside_dir(tmp_path):
4848
assert find_config_file() == cfg_file
4949

@@ -57,7 +57,7 @@ def test_returns_path_to_existing_file_in_correct_order(self, tmp_path: Path) ->
5757
expected_order = list(CONFIG_FILE_SEARCH_ORDER)[:] # make a copy so we can mutate it
5858
cfg_file_paths = [tmp_path / cfg_file_name for cfg_file_name in expected_order]
5959
for cfg_file in cfg_file_paths: # create all the files
60-
cfg_file.write_text('[tool.bumpversion]\ncurrent_version = "1.0.0"')
60+
cfg_file.write_text('[tool.bumpversion]\ncurrent_version = "1.0.0"', encoding="utf-8")
6161

6262
with inside_dir(tmp_path):
6363
while expected_order:
@@ -101,7 +101,7 @@ def test_returns_empty_dict_with_unknown_suffix(
101101
caplog.set_level("INFO")
102102
tmp_path = tmp_path_factory.mktemp("explicit-file-passed-")
103103
cfg_file = tmp_path / "basic_cfg.unknown"
104-
cfg_file.write_text('[tool.bumpversion]\ncurrent_version = "1.0.0"')
104+
cfg_file.write_text('[tool.bumpversion]\ncurrent_version = "1.0.0"', encoding="utf-8")
105105
with inside_dir(tmp_path):
106106
assert config.read_config_file(cfg_file) == {}
107107
assert "Unknown config file suffix" in caplog.text
@@ -132,9 +132,9 @@ def test_read_toml_file(conf_file: str, expected_file: str, fixtures_path: Path)
132132
def test_multiple_config_files(tmp_path: Path):
133133
"""If there are multiple config files, the first one with content wins."""
134134
setup_cfg = tmp_path / "setup.cfg"
135-
setup_cfg.write_text("[metadata]\nname: just-a-name\n")
135+
setup_cfg.write_text("[metadata]\nname: just-a-name\n", encoding="utf-8")
136136
bumpversion_cfg = tmp_path / ".bumpversion.cfg"
137-
bumpversion_cfg.write_text("\n")
137+
bumpversion_cfg.write_text("\n", encoding="utf-8")
138138
pyproject_toml = tmp_path / "pyproject.toml"
139139
pyproject_toml.write_text(
140140
"[tool.bumpversion]\n"
@@ -143,7 +143,8 @@ def test_multiple_config_files(tmp_path: Path):
143143
"serialize = [\n"
144144
' "{major}.{minor}.{patch}-{release}",\n'
145145
' "{major}.{minor}.{patch}"\n'
146-
"]\n"
146+
"]\n",
147+
encoding="utf-8",
147148
)
148149
with inside_dir(tmp_path):
149150
cfg_file = bumpversion.config.files.find_config_file()
@@ -180,7 +181,7 @@ def test_update_config_file(tmp_path: Path, cfg_file_name: str, fixtures_path: P
180181
expected_diff = TOML_EXPECTED_DIFF
181182
cfg_path = tmp_path / cfg_file_name
182183
orig_path = fixtures_path / f"basic_cfg{cfg_path.suffix}"
183-
cfg_path.write_text(orig_path.read_text())
184+
cfg_path.write_text(orig_path.read_text(), encoding="utf-8")
184185
original_content = orig_path.read_text().splitlines(keepends=True)
185186
with inside_dir(tmp_path):
186187
cfg = config.get_configuration(cfg_path)
@@ -206,9 +207,9 @@ def test_pep440_config(git_repo: Path, fixtures_path: Path):
206207

207208
cfg_path = git_repo / "pyproject.toml"
208209
orig_path = fixtures_path / "pep440.toml"
209-
cfg_path.write_text(orig_path.read_text())
210+
cfg_path.write_text(orig_path.read_text(), encoding="utf-8")
210211
version_path = git_repo / "VERSION"
211-
version_path.write_text("1.0.0")
212+
version_path.write_text("1.0.0", encoding="utf-8")
212213
readme_path = git_repo / "README.md"
213214
runner: CliRunner = CliRunner()
214215

@@ -225,7 +226,7 @@ def test_pep440_config(git_repo: Path, fixtures_path: Path):
225226
assert next_version_str == "1.0.1"
226227

227228
subprocess.run(["git", "checkout", "-b", "my-really-LONG-branch_name"], check=True, capture_output=True)
228-
readme_path.write_text("This is my branch!")
229+
readme_path.write_text("This is my branch!", encoding="utf-8")
229230
result: Result = runner.invoke(cli.cli, ["bump", "dev_label", "--no-tag"])
230231
assert result.exit_code == 0
231232
cfg = config.get_configuration(cfg_path)

tests/test_config/test_files_legacy.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ def test_independent_falsy_value_in_config_does_not_bump_independently(tmp_path:
6565
[bumpversion:part:build]
6666
independent = 0
6767
"""
68-
)
68+
),
69+
encoding="utf-8",
6970
)
7071

7172
conf = config.get_configuration(config_file)
@@ -113,7 +114,7 @@ def test_update_ini_config_file(tmp_path: Path, cfg_file_name: str, fixtures_pat
113114
expected_diff = CFG_EXPECTED_DIFF
114115
cfg_path = tmp_path / cfg_file_name
115116
orig_path = fixtures_path / f"basic_cfg{cfg_path.suffix}"
116-
cfg_path.write_text(orig_path.read_text())
117+
cfg_path.write_text(orig_path.read_text(), encoding="utf-8")
117118
original_content = orig_path.read_text().splitlines(keepends=True)
118119

119120
update_ini_config_file(cfg_path, "1.0.0", "1.0.1")
@@ -133,7 +134,8 @@ def test_file_keyword_with_suffix_is_accepted(tmp_path: Path, cfg_file: str, cfg
133134
"replace = version {new_version}\n"
134135
f"[bumpversion:{cfg_file_keyword}:file2]\n"
135136
"search = The current version is {current_version}\n"
136-
"replace = The current version is {new_version}\n"
137+
"replace = The current version is {new_version}\n",
138+
encoding="utf-8",
137139
)
138140
setup_cfg = config.get_configuration(cfg_file_path)
139141
assert len(setup_cfg.files) == 2

tests/test_config/test_utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def write_config(tmp_path: Path, overrides: dict) -> Path:
2222
defaults["current_version"] = defaults["current_version"] or "1.2.3"
2323
defaults["commit_args"] = ""
2424
config = {"tool": {"bumpversion": {**defaults, **overrides}}}
25-
config_file.write_text(tomlkit.dumps(config))
25+
config_file.write_text(tomlkit.dumps(config), encoding="utf-8")
2626
return config_file
2727

2828

0 commit comments

Comments
 (0)