Commit c8ae8684 by Randy Döring Committed by GitHub

Fix for tomlkit regression resulting in inconsistent line endings (#5870)

* init: use PyProjectTOML.save() instead of dumping content to string and writing string to file
* tests: adapt tests implicitly influenced by and add explicit test for consistent line endings in toml files
* require tomlkit >= 0.11.1 for consistent line endings
parent 81907610
...@@ -741,7 +741,7 @@ python-versions = ">=3.7" ...@@ -741,7 +741,7 @@ python-versions = ">=3.7"
[[package]] [[package]]
name = "tomlkit" name = "tomlkit"
version = "0.11.0" version = "0.11.1"
description = "Style preserving TOML library" description = "Style preserving TOML library"
category = "main" category = "main"
optional = false optional = false
...@@ -887,7 +887,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- ...@@ -887,7 +887,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.7" python-versions = "^3.7"
content-hash = "f7433da9d05dd21eb937d8f67e8324ae24cd85ad5655b421f636b648fae6b3a6" content-hash = "15542c18243196724e924f1145d082c3997843f33743544474a56747d144e480"
[metadata.files] [metadata.files]
atomicwrites = [ atomicwrites = [
...@@ -1401,8 +1401,8 @@ tomli = [ ...@@ -1401,8 +1401,8 @@ tomli = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
] ]
tomlkit = [ tomlkit = [
{file = "tomlkit-0.11.0-py3-none-any.whl", hash = "sha256:0f4050db66fd445b885778900ce4dd9aea8c90c4721141fde0d6ade893820ef1"}, {file = "tomlkit-0.11.1-py3-none-any.whl", hash = "sha256:1c5bebdf19d5051e2e1de6cf70adfc5948d47221f097fcff7a3ffc91e953eaf5"},
{file = "tomlkit-0.11.0.tar.gz", hash = "sha256:71ceb10c0eefd8b8f11fe34e8a51ad07812cb1dc3de23247425fbc9ddc47b9dd"}, {file = "tomlkit-0.11.1.tar.gz", hash = "sha256:61901f81ff4017951119cd0d1ed9b7af31c821d6845c8c477587bbdcd5e5854e"},
] ]
tox = [ tox = [
{file = "tox-3.25.0-py2.py3-none-any.whl", hash = "sha256:0805727eb4d6b049de304977dfc9ce315a1938e6619c3ab9f38682bb04662a5a"}, {file = "tox-3.25.0-py2.py3-none-any.whl", hash = "sha256:0805727eb4d6b049de304977dfc9ce315a1938e6619c3ab9f38682bb04662a5a"},
......
...@@ -62,7 +62,7 @@ platformdirs = "^2.5.2" ...@@ -62,7 +62,7 @@ platformdirs = "^2.5.2"
requests = "^2.18" requests = "^2.18"
requests-toolbelt = "^0.9.1" requests-toolbelt = "^0.9.1"
shellingham = "^1.1" shellingham = "^1.1"
tomlkit = ">=0.7.0,<1.0.0" tomlkit = ">=0.11.1,<1.0.0"
# exclude 20.4.5 - 20.4.6 due to https://github.com/pypa/pip/issues/9953 # exclude 20.4.5 - 20.4.6 due to https://github.com/pypa/pip/issues/9953
virtualenv = "(>=20.4.3,<20.4.5 || >=20.4.7)" virtualenv = "(>=20.4.3,<20.4.5 || >=20.4.7)"
xattr = { version = "^0.9.7", markers = "sys_platform == 'darwin'" } xattr = { version = "^0.9.7", markers = "sys_platform == 'darwin'" }
......
...@@ -219,11 +219,13 @@ You can specify a package in the following forms: ...@@ -219,11 +219,13 @@ You can specify a package in the following forms:
dev_dependencies=dev_requirements, dev_dependencies=dev_requirements,
) )
content = layout_.generate_poetry_content(original=pyproject) content = layout_.generate_poetry_content()
for section in content:
pyproject.data.append(section, content[section])
if self.io.is_interactive(): if self.io.is_interactive():
self.line("<info>Generated file</info>") self.line("<info>Generated file</info>")
self.line("") self.line("")
self.line(content) self.line(pyproject.data.as_string().replace("\r\n", "\n"))
self.line("") self.line("")
if not self.confirm("Do you confirm generation?", True): if not self.confirm("Do you confirm generation?", True):
...@@ -231,8 +233,7 @@ You can specify a package in the following forms: ...@@ -231,8 +233,7 @@ You can specify a package in the following forms:
return 1 return 1
with (Path.cwd() / "pyproject.toml").open("w", encoding="utf-8") as f: pyproject.save()
f.write(content)
return 0 return 0
......
...@@ -4,7 +4,7 @@ from pathlib import Path ...@@ -4,7 +4,7 @@ from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Any from typing import Any
from tomlkit import dumps from poetry.core.pyproject.toml import PyProjectTOML
from tomlkit import inline_table from tomlkit import inline_table
from tomlkit import loads from tomlkit import loads
from tomlkit import table from tomlkit import table
...@@ -17,7 +17,6 @@ from poetry.utils.helpers import module_name ...@@ -17,7 +17,6 @@ from poetry.utils.helpers import module_name
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Mapping from typing import Mapping
from poetry.core.pyproject.toml import PyProjectTOML
from tomlkit.items import InlineTable from tomlkit.items import InlineTable
...@@ -118,7 +117,7 @@ class Layout: ...@@ -118,7 +117,7 @@ class Layout:
self._write_poetry(path) self._write_poetry(path)
def generate_poetry_content(self, original: PyProjectTOML | None = None) -> str: def generate_poetry_content(self) -> TOMLDocument:
template = POETRY_DEFAULT template = POETRY_DEFAULT
content: dict[str, Any] = loads(template) content: dict[str, Any] = loads(template)
...@@ -171,12 +170,7 @@ class Layout: ...@@ -171,12 +170,7 @@ class Layout:
assert isinstance(content, TOMLDocument) assert isinstance(content, TOMLDocument)
content.add("build-system", build_system) content.add("build-system", build_system)
text = dumps(content) return content
if original and original.file.exists():
text = dumps(original.data) + "\n" + text
return text
def _create_default(self, path: Path, src: bool = True) -> None: def _create_default(self, path: Path, src: bool = True) -> None:
package_path = path / self.package_path package_path = path / self.package_path
...@@ -199,9 +193,8 @@ class Layout: ...@@ -199,9 +193,8 @@ class Layout:
tests_init.touch(exist_ok=False) tests_init.touch(exist_ok=False)
def _write_poetry(self, path: Path) -> None: def _write_poetry(self, path: Path) -> None:
pyproject = PyProjectTOML(path / "pyproject.toml")
content = self.generate_poetry_content() content = self.generate_poetry_content()
for section in content:
poetry = path / "pyproject.toml" pyproject.data.append(section, content[section])
pyproject.save()
with poetry.open("w", encoding="utf-8") as f:
f.write(content)
...@@ -870,12 +870,10 @@ Package operations: 1 install, 0 updates, 0 removals ...@@ -870,12 +870,10 @@ Package operations: 1 install, 0 updates, 0 removals
cachy = "^0.2.0" cachy = "^0.2.0"
""" """
# At the moment line endings will be inconsistent on Windows. string_content = content.as_string()
# See https://github.com/sdispater/tomlkit/issues/200 for details. if "\r\n" in string_content:
# https://github.com/sdispater/tomlkit/pull/201 fixes this issue # consistent line endings
# In order to make tests forward compatible for tomlkit downstream tests, expected = expected.replace("\n", "\r\n")
# we replace "\r\n" with "\n" for now.
string_content = content.as_string().replace("\r\n", "\n")
assert expected in string_content assert expected in string_content
......
...@@ -884,7 +884,6 @@ def test_add_package_with_extras_and_whitespace(tester: CommandTester): ...@@ -884,7 +884,6 @@ def test_add_package_with_extras_and_whitespace(tester: CommandTester):
assert "sqlite" in result[0]["extras"] assert "sqlite" in result[0]["extras"]
@pytest.mark.xfail(sys.platform == "win32", reason="regression in tomlkit")
def test_init_existing_pyproject_simple( def test_init_existing_pyproject_simple(
tester: CommandTester, tester: CommandTester,
source_dir: Path, source_dir: Path,
...@@ -901,7 +900,30 @@ line-length = 88 ...@@ -901,7 +900,30 @@ line-length = 88
assert f"{existing_section}\n{init_basic_toml}" in pyproject_file.read_text() assert f"{existing_section}\n{init_basic_toml}" in pyproject_file.read_text()
@pytest.mark.xfail(sys.platform == "win32", reason="regression in tomlkit") @pytest.mark.parametrize("linesep", ["\n", "\r\n"])
def test_init_existing_pyproject_consistent_linesep(
tester: CommandTester,
source_dir: Path,
init_basic_inputs: str,
init_basic_toml: str,
linesep: str,
):
pyproject_file = source_dir / "pyproject.toml"
existing_section = """
[tool.black]
line-length = 88
""".replace(
"\n", linesep
)
with open(pyproject_file, "w", newline="") as f:
f.write(existing_section)
tester.execute(inputs=init_basic_inputs)
with open(pyproject_file, newline="") as f:
content = f.read()
init_basic_toml = init_basic_toml.replace("\n", linesep)
assert f"{existing_section}{linesep}{init_basic_toml}" in content
def test_init_non_interactive_existing_pyproject_add_dependency( def test_init_non_interactive_existing_pyproject_add_dependency(
tester: CommandTester, tester: CommandTester,
source_dir: Path, source_dir: Path,
......
...@@ -91,12 +91,10 @@ baz = "^1.0.0" ...@@ -91,12 +91,10 @@ baz = "^1.0.0"
baz = "^1.0.0" baz = "^1.0.0"
""" """
# At the moment line endings will be inconsistent on Windows. string_content = content.as_string()
# See https://github.com/sdispater/tomlkit/issues/200 for details. if "\r\n" in string_content:
# https://github.com/sdispater/tomlkit/pull/201 fixes this issue # consistent line endings
# In order to make tests forward compatible for tomlkit downstream tests, expected = expected.replace("\n", "\r\n")
# we replace "\r\n" with "\n" for now.
string_content = content.as_string().replace("\r\n", "\n")
assert expected in string_content assert expected in string_content
...@@ -150,12 +148,10 @@ baz = "^1.0.0" ...@@ -150,12 +148,10 @@ baz = "^1.0.0"
baz = "^1.0.0" baz = "^1.0.0"
""" """
# At the moment line endings will be inconsistent on Windows. string_content = content.as_string()
# See https://github.com/sdispater/tomlkit/issues/200 for details. if "\r\n" in string_content:
# https://github.com/sdispater/tomlkit/pull/201 fixes this issue # consistent line endings
# In order to make tests forward compatible for tomlkit downstream tests, expected = expected.replace("\n", "\r\n")
# we replace "\r\n" with "\n" for now.
string_content = content.as_string().replace("\r\n", "\n")
assert expected in string_content assert expected in string_content
...@@ -257,12 +253,10 @@ baz = "^1.0.0" ...@@ -257,12 +253,10 @@ baz = "^1.0.0"
baz = "^1.0.0" baz = "^1.0.0"
""" """
# At the moment line endings will be inconsistent on Windows. string_content = content.as_string()
# See https://github.com/sdispater/tomlkit/issues/200 for details. if "\r\n" in string_content:
# https://github.com/sdispater/tomlkit/pull/201 fixes this issue # consistent line endings
# In order to make tests forward compatible for tomlkit downstream tests, expected = expected.replace("\n", "\r\n")
# we replace "\r\n" with "\n" for now.
string_content = content.as_string().replace("\r\n", "\n")
assert expected in string_content assert expected in string_content
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment