Skip to content
Open
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
10 changes: 6 additions & 4 deletions src/poetry/masonry/builders/editable.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@
sys.exit({callable_}())
"""

WINDOWS_CMD_TEMPLATE = """\
@echo off\r\n"{python}" "%~dp0\\{script}" %*\r\n
"""
# The .cmd wrapper is written as UTF-8. Switch cmd.exe to UTF-8 before it
# parses paths so non-ASCII virtualenv locations are handled correctly.
WINDOWS_CMD_TEMPLATE = (
Comment on lines +39 to +41

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

question: Consider whether unconditionally forcing code page 65001 is safe for all environments that use this wrapper.

Changing the active code page will affect all subsequent commands in that cmd.exe session (including subprocesses spawned by Python). Given this wrapper runs in diverse contexts (CI, editors, etc.), please verify that always running chcp 65001 won’t break cases that rely on a non‑UTF‑8 console. If that’s a risk, consider gating this behind an env flag or only enabling it when non‑ASCII paths are detected.

'@echo off\r\nchcp 65001 >nul\r\n"{python}" "%~dp0\\{script}" %*\r\n'
)


class EditableBuilder(Builder):
Expand Down Expand Up @@ -206,7 +208,7 @@ def _add_scripts(self) -> list[Path]:
f" <b>{scripts_path}</b>"
)

with cmd_script.open("w", encoding="utf-8") as f:
with cmd_script.open("w", encoding="utf-8", newline="") as f:
f.write(decode(cmd))

added.append(cmd_script)
Expand Down
24 changes: 24 additions & 0 deletions tests/masonry/builders/test_editable_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,30 @@ def test_builder_installs_proper_files_for_standard_packages(
assert tmp_venv._bin_dir.joinpath("fox").read_text(encoding="utf-8") == fox_script


def test_builder_windows_cmd_wrapper_uses_utf8_code_page_for_non_ascii_paths(
simple_poetry: Poetry, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
class WindowsScriptEnv(MockEnv):
@property
def python(self) -> Path:
return Path(
r"C:\Users\jmoni\OneDrive\Área de Trabalho\example\.venv\Scripts\python.exe"
)

env = WindowsScriptEnv(path=tmp_path / "Área de Trabalho" / ".venv")
python = env.python

monkeypatch.setattr("poetry.masonry.builders.editable.WINDOWS", True)

builder = EditableBuilder(simple_poetry, env, NullIO())
builder._add_scripts()

assert (
env.script_dirs[0].joinpath("foo.cmd").read_bytes()
== (f'@echo off\r\nchcp 65001 >nul\r\n"{python}" "%~dp0\\foo" %*\r\n').encode()
)


def test_builder_falls_back_on_setup_and_pip_for_packages_with_build_scripts(
mocker: MockerFixture, extended_poetry: Poetry, tmp_path: Path
) -> None:
Expand Down
Loading