From 3baf11b167afdf90853d901e0caa597fc634a1ff Mon Sep 17 00:00:00 2001 From: Nardi Lam Date: Thu, 16 Nov 2023 17:47:47 +0100 Subject: [PATCH 1/3] Change write_bytes to write_text to preserve newlines --- poetry_dynamic_versioning/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry_dynamic_versioning/__init__.py b/poetry_dynamic_versioning/__init__.py index 49c747e..7f8ffc9 100644 --- a/poetry_dynamic_versioning/__init__.py +++ b/poetry_dynamic_versioning/__init__.py @@ -473,7 +473,7 @@ def _substitute_version(name: str, version: str, folders: Sequence[_FolderConfig new_content = _substitute_version_in_text(version, original_content, config.patterns) if original_content != new_content: _state.projects[name].substitutions[file] = original_content - file.write_bytes(new_content.encode("utf-8")) + file.write_text(new_content, encoding="utf-8") def _substitute_version_in_text(version: str, content: str, patterns: Sequence[_SubPattern]) -> str: @@ -519,7 +519,7 @@ def _apply_version( if not retain and not _state.cli_mode: pyproject["tool"]["poetry-dynamic-versioning"]["enable"] = False # type: ignore - pyproject_path.write_bytes(tomlkit.dumps(pyproject).encode("utf-8")) + pyproject_path.write_text(tomlkit.dumps(pyproject), encoding="utf-8") name = pyproject["tool"]["poetry"]["name"] # type: ignore @@ -530,7 +530,7 @@ def _apply_version( if not full_file.parent.exists(): full_file.parent.mkdir() initial = textwrap.dedent(file_info["initial-content"]) - full_file.write_bytes(initial.encode("utf-8")) + full_file.write_text(initial, encoding="utf-8") _substitute_version( name, # type: ignore @@ -604,7 +604,7 @@ def _revert_version(retain: bool = False) -> None: if file in persistent: continue - file.write_bytes(content.encode("utf-8")) + file.write_text(content, encoding="utf-8") # Reread pyproject.toml in case the substitutions affected it. pyproject = tomlkit.parse(state.path.read_text(encoding="utf-8")) @@ -614,6 +614,6 @@ def _revert_version(retain: bool = False) -> None: if not retain and not _state.cli_mode: pyproject["tool"]["poetry-dynamic-versioning"]["enable"] = True # type: ignore - state.path.write_bytes(tomlkit.dumps(pyproject).encode("utf-8")) + state.path.write_text(tomlkit.dumps(pyproject), encoding="utf-8") _state.projects.clear() From 5d5444bb3de6b0566a01191c540bad888d976a26 Mon Sep 17 00:00:00 2001 From: mtkennerly Date: Sat, 2 Dec 2023 15:27:48 +0800 Subject: [PATCH 2/3] Revert "Change write_bytes to write_text to preserve newlines" This reverts commit 3baf11b167afdf90853d901e0caa597fc634a1ff. --- poetry_dynamic_versioning/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry_dynamic_versioning/__init__.py b/poetry_dynamic_versioning/__init__.py index 7f8ffc9..49c747e 100644 --- a/poetry_dynamic_versioning/__init__.py +++ b/poetry_dynamic_versioning/__init__.py @@ -473,7 +473,7 @@ def _substitute_version(name: str, version: str, folders: Sequence[_FolderConfig new_content = _substitute_version_in_text(version, original_content, config.patterns) if original_content != new_content: _state.projects[name].substitutions[file] = original_content - file.write_text(new_content, encoding="utf-8") + file.write_bytes(new_content.encode("utf-8")) def _substitute_version_in_text(version: str, content: str, patterns: Sequence[_SubPattern]) -> str: @@ -519,7 +519,7 @@ def _apply_version( if not retain and not _state.cli_mode: pyproject["tool"]["poetry-dynamic-versioning"]["enable"] = False # type: ignore - pyproject_path.write_text(tomlkit.dumps(pyproject), encoding="utf-8") + pyproject_path.write_bytes(tomlkit.dumps(pyproject).encode("utf-8")) name = pyproject["tool"]["poetry"]["name"] # type: ignore @@ -530,7 +530,7 @@ def _apply_version( if not full_file.parent.exists(): full_file.parent.mkdir() initial = textwrap.dedent(file_info["initial-content"]) - full_file.write_text(initial, encoding="utf-8") + full_file.write_bytes(initial.encode("utf-8")) _substitute_version( name, # type: ignore @@ -604,7 +604,7 @@ def _revert_version(retain: bool = False) -> None: if file in persistent: continue - file.write_text(content, encoding="utf-8") + file.write_bytes(content.encode("utf-8")) # Reread pyproject.toml in case the substitutions affected it. pyproject = tomlkit.parse(state.path.read_text(encoding="utf-8")) @@ -614,6 +614,6 @@ def _revert_version(retain: bool = False) -> None: if not retain and not _state.cli_mode: pyproject["tool"]["poetry-dynamic-versioning"]["enable"] = True # type: ignore - state.path.write_text(tomlkit.dumps(pyproject), encoding="utf-8") + state.path.write_bytes(tomlkit.dumps(pyproject).encode("utf-8")) _state.projects.clear() From d145dc48bd36f07eec80759566f599e4076173ea Mon Sep 17 00:00:00 2001 From: mtkennerly Date: Sat, 2 Dec 2023 15:30:43 +0800 Subject: [PATCH 3/3] #157: Use read_bytes() instead of read_text() to preserve line ending style --- CHANGELOG.md | 7 ++++ poetry_dynamic_versioning/__init__.py | 14 +++---- poetry_dynamic_versioning/cli.py | 2 +- tests/test_integration.py | 54 ++++++++++++++++----------- 4 files changed, 48 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecf5f63..0faa731 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## Unreleased + +* Fixed: + * Line ending style was not preserved in some cases because of the default behavior of `pathlib.Path.read_text`. + To avoid this, `pathlib.Path.read_bytes` is used instead now. + ([Contributed by nardi](https://github.com/mtkennerly/poetry-dynamic-versioning/pull/157)) + ## v1.1.1 (2023-10-27) * Fixed: diff --git a/poetry_dynamic_versioning/__init__.py b/poetry_dynamic_versioning/__init__.py index 49c747e..37c23f9 100644 --- a/poetry_dynamic_versioning/__init__.py +++ b/poetry_dynamic_versioning/__init__.py @@ -277,7 +277,7 @@ def _get_config_from_path(start: Optional[Path] = None) -> Mapping: pyproject_path = _get_pyproject_path(start) if pyproject_path is None: return _default_config()["tool"]["poetry-dynamic-versioning"] - pyproject = tomlkit.parse(pyproject_path.read_text(encoding="utf-8")) + pyproject = tomlkit.parse(pyproject_path.read_bytes().decode("utf-8")) result = _get_config(pyproject) return result @@ -287,7 +287,7 @@ def _validate_config(config: Optional[Mapping] = None) -> Sequence[str]: pyproject_path = _get_pyproject_path() if pyproject_path is None: raise RuntimeError("Unable to find pyproject.toml") - config = tomlkit.parse(pyproject_path.read_text(encoding="utf-8")) + config = tomlkit.parse(pyproject_path.read_bytes().decode("utf-8")) return _validate_config_section( config.get("tool", {}).get("poetry-dynamic-versioning", {}), @@ -469,7 +469,7 @@ def _substitute_version(name: str, version: str, folders: Sequence[_FolderConfig files[resolved] = folder for file, config in files.items(): - original_content = file.read_text(encoding="utf-8") + original_content = file.read_bytes().decode("utf-8") new_content = _substitute_version_in_text(version, original_content, config.patterns) if original_content != new_content: _state.projects[name].substitutions[file] = original_content @@ -509,7 +509,7 @@ def _substitute_version_in_text(version: str, content: str, patterns: Sequence[_ def _apply_version( version: str, config: _Config, pyproject_path: Path, retain: bool = False ) -> None: - pyproject = tomlkit.parse(pyproject_path.read_text(encoding="utf-8")) + pyproject = tomlkit.parse(pyproject_path.read_bytes().decode("utf-8")) pyproject["tool"]["poetry"]["version"] = version # type: ignore @@ -559,7 +559,7 @@ def _get_and_apply_version( raise RuntimeError("Unable to find pyproject.toml") if pyproject is None: - pyproject = tomlkit.parse(pyproject_path.read_text(encoding="utf-8")) + pyproject = tomlkit.parse(pyproject_path.read_bytes().decode("utf-8")) if name is None or original is None: name = pyproject["tool"]["poetry"]["name"] @@ -590,7 +590,7 @@ def _get_and_apply_version( def _revert_version(retain: bool = False) -> None: for project, state in _state.projects.items(): - pyproject = tomlkit.parse(state.path.read_text(encoding="utf-8")) + pyproject = tomlkit.parse(state.path.read_bytes().decode("utf-8")) if state.substitutions: config = _get_config(pyproject) @@ -607,7 +607,7 @@ def _revert_version(retain: bool = False) -> None: file.write_bytes(content.encode("utf-8")) # Reread pyproject.toml in case the substitutions affected it. - pyproject = tomlkit.parse(state.path.read_text(encoding="utf-8")) + pyproject = tomlkit.parse(state.path.read_bytes().decode("utf-8")) pyproject["tool"]["poetry"]["version"] = state.original_version # type: ignore diff --git a/poetry_dynamic_versioning/cli.py b/poetry_dynamic_versioning/cli.py index 67c50d5..ce99c20 100644 --- a/poetry_dynamic_versioning/cli.py +++ b/poetry_dynamic_versioning/cli.py @@ -90,7 +90,7 @@ def enable() -> None: pyproject_path = _get_pyproject_path() if pyproject_path is None: raise RuntimeError("Unable to find pyproject.toml") - config = tomlkit.parse(pyproject_path.read_text(encoding="utf-8")) + config = tomlkit.parse(pyproject_path.read_bytes().decode("utf-8")) config = _enable_in_doc(config) pyproject_path.write_bytes(tomlkit.dumps(config).encode("utf-8")) diff --git a/tests/test_integration.py b/tests/test_integration.py index 2960d48..0030cb5 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -88,7 +88,7 @@ def test_plugin_enabled(): def test_plugin_disabled(): - data = DUMMY_PYPROJECT.read_text("utf8") + data = DUMMY_PYPROJECT.read_bytes().decode("utf-8") data = data.replace("enable = true", "enable = false") DUMMY_PYPROJECT.write_bytes(data.encode("utf-8")) @@ -98,7 +98,7 @@ def test_plugin_disabled(): def test_plugin_disabled_without_plugin_section(): - data = DUMMY_PYPROJECT.read_text("utf8") + data = DUMMY_PYPROJECT.read_bytes().decode("utf-8") data = data.replace("[tool.poetry-dynamic-versioning]", "[tool.poetry-dynamic-versioning-x]") DUMMY_PYPROJECT.write_bytes(data.encode("utf-8")) @@ -113,7 +113,7 @@ def test_plugin_disabled_without_pyproject_file(): def test_invalid_config_for_vcs(): - data = DUMMY_PYPROJECT.read_text("utf8") + data = DUMMY_PYPROJECT.read_bytes().decode("utf-8") data = data.replace('vcs = "git"', 'vcs = "invalid"') DUMMY_PYPROJECT.write_bytes(data.encode("utf-8")) @@ -125,7 +125,7 @@ def test_keep_pyproject_modifications(): # Using --optional to avoid actually installing the package run(f"poetry add --optional {package}", where=DUMMY) # Make sure pyproject.toml contains the new package dependency - data = DUMMY_PYPROJECT.read_text("utf8") + data = DUMMY_PYPROJECT.read_bytes().decode("utf-8") assert package in data @@ -133,7 +133,7 @@ def test_poetry_run(): # The original version is restored before the command runs: run(f"poetry run grep 'version = \"{DUMMY_VERSION}\"' pyproject.toml", where=DUMMY) # Make sure original version number is still in place: - data = DUMMY_PYPROJECT.read_text("utf8") + data = DUMMY_PYPROJECT.read_bytes().decode("utf-8") assert f'version = "{DUMMY_VERSION}"' in data @@ -141,48 +141,60 @@ def test_poetry_run(): def test_poetry_shell(): # Make sure original version number is still in place afterwards: run("poetry shell", where=DUMMY) - data = DUMMY_PYPROJECT.read_text("utf8") + data = DUMMY_PYPROJECT.read_bytes().decode("utf-8") assert f'version = "{DUMMY_VERSION}"' in data def test_plugin_cli_mode_and_substitution(): run("poetry dynamic-versioning", where=DUMMY) # Changes persist after the command is done: - assert f'version = "{DUMMY_VERSION}"' not in DUMMY_PYPROJECT.read_text("utf8") - assert '__version__: str = "0.0.0"' not in (DUMMY / "project" / "__init__.py").read_text("utf8") - assert '__version__ = "0.0.0"' not in (DUMMY / "project" / "__init__.py").read_text("utf8") + assert f'version = "{DUMMY_VERSION}"' not in DUMMY_PYPROJECT.read_bytes().decode("utf-8") + assert '__version__: str = "0.0.0"' not in ( + DUMMY / "project" / "__init__.py" + ).read_bytes().decode("utf-8") + assert '__version__ = "0.0.0"' not in (DUMMY / "project" / "__init__.py").read_bytes().decode( + "utf-8" + ) assert "__version_tuple__ = (0, 0, 0)" not in (DUMMY / "project" / "__init__.py").read_text( "utf8" ) - assert "<0.0.0>" not in (DUMMY / "project" / "__init__.py").read_text("utf8") + assert "<0.0.0>" not in (DUMMY / "project" / "__init__.py").read_bytes().decode("utf-8") def test_standalone_cli_mode_and_substitution(): run("poetry-dynamic-versioning", where=DUMMY) # Changes persist after the command is done: - assert f'version = "{DUMMY_VERSION}"' not in DUMMY_PYPROJECT.read_text("utf8") - assert '__version__: str = "0.0.0"' not in (DUMMY / "project" / "__init__.py").read_text("utf8") - assert '__version__ = "0.0.0"' not in (DUMMY / "project" / "__init__.py").read_text("utf8") + assert f'version = "{DUMMY_VERSION}"' not in DUMMY_PYPROJECT.read_bytes().decode("utf-8") + assert '__version__: str = "0.0.0"' not in ( + DUMMY / "project" / "__init__.py" + ).read_bytes().decode("utf-8") + assert '__version__ = "0.0.0"' not in (DUMMY / "project" / "__init__.py").read_bytes().decode( + "utf-8" + ) assert "__version_tuple__ = (0, 0, 0)" not in (DUMMY / "project" / "__init__.py").read_text( "utf8" ) - assert "<0.0.0>" not in (DUMMY / "project" / "__init__.py").read_text("utf8") + assert "<0.0.0>" not in (DUMMY / "project" / "__init__.py").read_bytes().decode("utf-8") def test_cli_mode_and_substitution_without_enable(): - data = DUMMY_PYPROJECT.read_text("utf8") + data = DUMMY_PYPROJECT.read_bytes().decode("utf-8") data = data.replace("enable = true", "enable = false") DUMMY_PYPROJECT.write_bytes(data.encode("utf-8")) run("poetry dynamic-versioning", where=DUMMY) # Changes persist after the command is done: - assert f'version = "{DUMMY_VERSION}"' not in DUMMY_PYPROJECT.read_text("utf8") - assert '__version__: str = "0.0.0"' not in (DUMMY / "project" / "__init__.py").read_text("utf8") - assert '__version__ = "0.0.0"' not in (DUMMY / "project" / "__init__.py").read_text("utf8") + assert f'version = "{DUMMY_VERSION}"' not in DUMMY_PYPROJECT.read_bytes().decode("utf-8") + assert '__version__: str = "0.0.0"' not in ( + DUMMY / "project" / "__init__.py" + ).read_bytes().decode("utf-8") + assert '__version__ = "0.0.0"' not in (DUMMY / "project" / "__init__.py").read_bytes().decode( + "utf-8" + ) assert "__version_tuple__ = (0, 0, 0)" not in (DUMMY / "project" / "__init__.py").read_text( "utf8" ) - assert "<0.0.0>" not in (DUMMY / "project" / "__init__.py").read_text("utf8") + assert "<0.0.0>" not in (DUMMY / "project" / "__init__.py").read_bytes().decode("utf-8") def test_cli_mode_plus_build_will_disable_plugin(): @@ -210,7 +222,7 @@ def test_poetry_core_as_build_system(): dist = project / "dist" pyproject = project / "pyproject.toml" - data = pyproject.read_text("utf8") + data = pyproject.read_bytes().decode("utf-8") data = re.sub( r"requires = .*", 'requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"]', @@ -229,7 +241,7 @@ def test_poetry_core_as_build_system(): def test_bumping_enabled(): - data = DUMMY_PYPROJECT.read_text("utf8") + data = DUMMY_PYPROJECT.read_bytes().decode("utf-8") data = data.replace('vcs = "git"', "bump = true") data = data.replace('style = "semver"', 'style = "pep440"') DUMMY_PYPROJECT.write_bytes(data.encode("utf-8"))