Skip to content

fix: use explicit encodings in cz commit --edit and cz init - #2119

Open
Alpenj wants to merge 3 commits into
commitizen-tools:masterfrom
Alpenj:fix-edit-message-encoding
Open

Alpenj wants to merge 3 commits into
commitizen-tools:masterfrom
Alpenj:fix-edit-message-encoding

Conversation

@Alpenj

@Alpenj Alpenj commented Nov 6, 2026 •

Copy link
Copy Markdown

Description

On Windows, the locale encoding is a legacy code page (for example cp1252, or cp949 on Korean Windows). Two code paths used it for text that is often outside that code page:

  • cz commit --edit wrote the message to a temporary file with the locale encoding and read it back the same way. A message with characters outside the code page failed before the editor opened:
    UnicodeEncodeError: 'cp949' codec can't encode character '\u2728' in position 25: illegal multibyte sequence
    It now uses the new commit_encoding setting. When it is not set, it uses encoding ("utf-8" by default). A file that the editor saves as UTF-8 is also read back correctly.
  • cz init read pyproject.toml with the locale encoding to choose the default version provider. TOML files are UTF-8, so a pyproject.toml with non-ASCII text (for example an author name) failed:
    UnicodeDecodeError: 'cp949' codec can't decode byte 0xe2 in position 50: illegal multibyte sequence
    It now reads the file as UTF-8.

commit_encoding also applies to the other files that hold a commit message: the --write-message-to-file file, the --retry backup file and the cz check --commit-msg-file file. They already used encoding, so they do not change by default.

Checklist

Was generative AI tooling used to co-author this PR?

  • Yes (please specify the tool below)

Generated-by: Claude Code (claude-opus-5-5) following the guidelines

Assisted By: AI

Code Changes

  • Add test cases to all the changes you introduce
  • Run uv run poe all locally to ensure this change passes linter check and tests
  • Manually test the changes:
    • Verify the feature/bug fix works as expected in real-world scenarios
    • Test edge cases and error conditions
    • Ensure backward compatibility is maintained
    • Document any manual testing steps performed
  • Update the documentation for the changes

Expected Behavior

cz commit --edit and cz init work with non-ASCII text whatever the locale encoding is.

Steps to Test This Pull Request

  1. On Windows with a non-UTF-8 code page, run pytest tests/commands/test_commit_command.py tests/commands/test_check_command.py tests/test_project_info.py.
  2. Without this change, test_manual_edit_keeps_non_ascii_message and the new test_get_default_version_provider case fail with the errors above. With this change, they pass.

Additional Context

What I ran on Windows 11 (cp949), Python 3.12, instead of uv run poe all:

  • With the source files from master, the new tests fail. With this PR, tests/commands/test_commit_command.py, tests/commands/test_check_command.py, tests/test_conf.py, tests/test_project_info.py and tests/commands/test_init_command.py pass (204 passed).
  • cz check --rev-range origin/master.. and ruff check pass. mypy reports no errors in the changed files; it reports the same 17 errors on master with the dependency versions installed here.

I did not run the full test suite with coverage. On Linux and macOS the locale encoding is usually UTF-8, so the new tests pass there with or without the fix; the Windows CI job runs them with the runner's cp1252 code page.

This PR was prepared and opened by Claude Code, an AI agent, on behalf of the account owner.

🤖 Generated with Claude Code

Alpenj and others added 2 commits November 6, 2026 08:44
`cz commit --edit` wrote the message to a temporary file with the locale
encoding and read it back the same way. On Windows the locale encoding is
a legacy code page (for example cp1252), so a message with characters
outside it failed with a UnicodeEncodeError, and a file that the editor
saved as UTF-8 was decoded incorrectly. Use the `encoding` setting, as the
other commit message files do.

Assisted By: AI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`get_default_version_provider` read pyproject.toml with the locale
encoding. TOML files are UTF-8, so on Windows a pyproject.toml with
non-ASCII text (for example an author name) made `cz init` fail with a
UnicodeDecodeError.

Assisted By: AI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.29%. Comparing base (f690817) to head (c00f5dc).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2119   +/-   ##
=======================================
  Coverage   98.28%   98.29%           
=======================================
  Files          61       61           
  Lines        2864     2868    +4     
=======================================
+ Hits         2815     2819    +4     
  Misses         49       49           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@woile woile left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to the change, a few details

Comment thread commitizen/commands/commit.py Outdated
if exec_path is None:
raise RuntimeError(f"Editor '{editor}' not found.")
with tempfile.NamedTemporaryFile(mode="w", delete=False) as file:
encoding = self.config.settings["encoding"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be commit_encoding and it should be initialized in

class Settings(TypedDict, total=False):

It should also have a default in
https://github.com/commitizen-tools/commitizen/blob/master/commitizen/defaults.py#L82-L88

Should the commit_encoding default be utf-8 or should it be None?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in c00f5dc. The default is None, which means "use encoding". So existing configs keep the same behavior, and the --edit file is still UTF-8 by default.

I also applied commit_encoding to the other files that hold a commit message: --write-message-to-file, the --retry backup and cz check --commit-msg-file. They already used encoding, so nothing changes by default, and one setting now controls all commit message files.

I documented it in docs/config/commit.md.

`commit_encoding` sets the encoding of the files that hold a commit
message: the `cz commit --edit` file, the `--write-message-to-file`
file, the `--retry` backup file and the `cz check --commit-msg-file`
file. The default is `None`, which means `encoding`. The last three
files already use `encoding`, so they do not change by default.

Assisted By: AI

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants