diff --git a/docs/managing-dependencies.md b/docs/managing-dependencies.md index 59f308c2508..80865d46c9a 100644 --- a/docs/managing-dependencies.md +++ b/docs/managing-dependencies.md @@ -24,17 +24,33 @@ Poetry provides a way to **organize** your dependencies by **groups**. The dependencies declared in `project.dependencies` respectively `tool.poetry.dependencies` are part of an implicit `main` group. Those dependencies are required by your project during runtime. -Beside the `main` dependencies, you might have dependencies that are only needed to test your project +Besides the `main` dependencies, you might have dependencies that are only needed to test your project or to build the documentation. -To declare a new dependency group, use a `tool.poetry.group.` section -where `` is the name of your dependency group (for instance, `test`): +To declare a new dependency group, use a `dependency-groups` section according to PEP 735 or +a `tool.poetry.group.` section where `` is the name of your dependency group (for instance, `test`): +{{< tabs tabTotal="2" tabID1="group-pep735" tabID2="group-poetry" tabName1="[dependency-groups]" tabName2="[tool.poetry]">}} + +{{< tab tabID="group-pep735" >}} +```toml +[dependency-groups] +test = [ + "pytest (>=6.0.0,<7.0.0)", + "pytest-mock", +] +``` +{{< /tab >}} + +{{< tab tabID="group-poetry" >}} ```toml [tool.poetry.group.test.dependencies] pytest = "^6.0.0" pytest-mock = "*" ``` +{{< /tab >}} +{{< /tabs >}} + {{% note %}} All dependencies **must be compatible with each other** across groups since they will @@ -60,6 +76,21 @@ A dependency group can be declared as optional. This makes sense when you have a group of dependencies that are only required in a particular environment or for a specific purpose. +{{< tabs tabTotal="2" tabID1="group-optional-pep735" tabID2="group-optional-poetry" tabName1="[dependency-groups]" tabName2="[tool.poetry]">}} + +{{< tab tabID="group-optional-pep735" >}} +```toml +[dependency-groups] +docs = [ + "mkdocs", +] + +[tool.poetry.group.docs] +optional = true +``` +{{< /tab >}} + +{{< tab tabID="group-optional-poetry" >}} ```toml [tool.poetry.group.docs] optional = true @@ -67,6 +98,10 @@ optional = true [tool.poetry.group.docs.dependencies] mkdocs = "*" ``` +{{< /tab >}} +{{< /tabs >}} + + Optional groups can be installed in addition to the **default** dependencies by using the `--with` option of the [`install`]({{< relref "cli#install" >}}) command. diff --git a/poetry.lock b/poetry.lock index 653044bcef1..e88e88a8bb5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1186,7 +1186,7 @@ develop = false type = "git" url = "https://github.com/python-poetry/poetry-core.git" reference = "HEAD" -resolved_reference = "41702651de85c3d100607c7c53579d0164b2969d" +resolved_reference = "2d18c0e8b05f538bbfeb56076aee7c49a54085cb" [[package]] name = "pre-commit" diff --git a/src/poetry/console/commands/add.py b/src/poetry/console/commands/add.py index 0bb306eb077..a6f1c02df1d 100644 --- a/src/poetry/console/commands/add.py +++ b/src/poetry/console/commands/add.py @@ -152,6 +152,7 @@ def handle(self) -> int: content: dict[str, Any] = self.poetry.file.read() project_content = content.get("project", table()) poetry_content = content.get("tool", {}).get("poetry", table()) + groups_content = content.get("dependency-groups", {}) project_name = ( canonicalize_name(name) if (name := project_content.get("name", poetry_content.get("name"))) @@ -159,7 +160,10 @@ def handle(self) -> int: ) use_project_section = False + use_groups_section = False project_dependency_names = [] + + # Run-Time Deps incl. extras if group == MAIN_GROUP: if ( "dependencies" in project_content @@ -179,22 +183,26 @@ def handle(self) -> int: project_section = array() poetry_section = poetry_content.get("dependencies", table()) - else: - if "group" not in poetry_content: - poetry_content["group"] = table(is_super_table=True) - - groups = poetry_content["group"] - - if group not in groups: - groups[group] = table() - groups.add(nl()) - this_group = groups[group] + # Dependency Groups + else: + if groups_content or "group" not in poetry_content: + use_groups_section = True + if not groups_content: + groups_content = table(is_super_table=True) + if group not in groups_content: + groups_content[group] = array("[\n]") - if "dependencies" not in this_group: - this_group["dependencies"] = table() + project_dependency_names = [ + Dependency.create_from_pep_508(dep).name + for dep in groups_content[group] + ] - poetry_section = this_group["dependencies"] + poetry_section = ( + poetry_content.get("group", {}) + .get(group, {}) + .get("dependencies", table()) + ) project_section = [] existing_packages = self.get_existing_packages_from_input( @@ -263,17 +271,17 @@ def handle(self) -> int: self.line_error("\nNo changes were applied.") return 1 - if self.option("python"): - constraint["python"] = self.option("python") + if python := self.option("python"): + constraint["python"] = python - if self.option("platform"): - constraint["platform"] = self.option("platform") + if platform := self.option("platform"): + constraint["platform"] = platform - if self.option("markers"): - constraint["markers"] = self.option("markers") + if markers := self.option("markers"): + constraint["markers"] = markers - if self.option("source"): - constraint["source"] = self.option("source") + if source := self.option("source"): + constraint["source"] = source if len(constraint) == 1 and "version" in constraint: constraint = constraint["version"] @@ -304,13 +312,16 @@ def handle(self) -> int: ) self.poetry.package.add_dependency(dependency) - if use_project_section: + if use_project_section or use_groups_section: + pep_section = ( + project_section if use_project_section else groups_content[group] + ) try: index = project_dependency_names.index(canonical_constraint_name) except ValueError: - project_section.append(dependency.to_pep_508()) + pep_section.append(dependency.to_pep_508()) else: - project_section[index] = dependency.to_pep_508() + pep_section[index] = dependency.to_pep_508() # create a second constraint for tool.poetry.dependencies with keys # that cannot be stored in the project section @@ -352,13 +363,33 @@ def handle(self) -> int: project_content["optional-dependencies"][optional] = project_section elif "dependencies" not in project_content: project_content["dependencies"] = project_section + if poetry_section: if "tool" not in content: content["tool"] = table() if "poetry" not in content["tool"]: content["tool"]["poetry"] = poetry_content - if group == MAIN_GROUP and "dependencies" not in poetry_content: - poetry_content["dependencies"] = poetry_section + if group == MAIN_GROUP: + if "dependencies" not in poetry_content: + poetry_content["dependencies"] = poetry_section + else: + if "group" not in poetry_content: + poetry_content["group"] = table(is_super_table=True) + + groups = poetry_content["group"] + + if group not in groups: + groups[group] = table() + groups.add(nl()) + + if "dependencies" not in groups[group]: + groups[group]["dependencies"] = poetry_section + + if groups_content and group != MAIN_GROUP: + if "dependency-groups" not in content: + content["dependency-groups"] = table() + content["dependency-groups"][group] = groups_content[group] + self.poetry.locker.set_pyproject_data(content) self.installer.set_locker(self.poetry.locker) diff --git a/src/poetry/console/commands/remove.py b/src/poetry/console/commands/remove.py index 1cb4da54509..ef7a0fbf97f 100644 --- a/src/poetry/console/commands/remove.py +++ b/src/poetry/console/commands/remove.py @@ -63,7 +63,9 @@ def handle(self) -> int: content: dict[str, Any] = self.poetry.file.read() project_content = content.get("project", {}) + groups_content = content.get("dependency-groups", {}) poetry_content = content.get("tool", {}).get("poetry", {}) + poetry_groups_content = poetry_content.get("group", {}) if group is None: # remove from all groups @@ -71,21 +73,38 @@ def handle(self) -> int: group_sections = [] project_dependencies = project_content.get("dependencies", []) poetry_dependencies = poetry_content.get("dependencies", {}) + if project_dependencies or poetry_dependencies: group_sections.append( (MAIN_GROUP, project_dependencies, poetry_dependencies) ) + group_sections.extend( + ( + group_name, + dependencies, + poetry_groups_content.get(group_name, {}).get("dependencies", {}), + ) + for group_name, dependencies in groups_content.items() + ) group_sections.extend( (group_name, [], group_section.get("dependencies", {})) - for group_name, group_section in poetry_content.get("group", {}).items() + for group_name, group_section in poetry_groups_content.items() + if group_name not in groups_content and group_name != MAIN_GROUP ) - for group_name, project_section, poetry_section in group_sections: + for group_name, standard_section, poetry_section in group_sections: removed |= self._remove_packages( - packages, project_section, poetry_section, group_name + packages=packages, + standard_section=standard_section, + poetry_section=poetry_section, + group_name=group_name, ) - if group_name != MAIN_GROUP and not poetry_section: - del poetry_content["group"][group_name] + if group_name != MAIN_GROUP: + if not poetry_section and group_name in poetry_groups_content: + del poetry_content["group"][group_name] + if not standard_section and group_name in groups_content: + del groups_content[group_name] + elif group == "dev" and "dev-dependencies" in poetry_content: # We need to account for the old `dev-dependencies` section removed = self._remove_packages( @@ -98,18 +117,35 @@ def handle(self) -> int: removed = set() if "group" in poetry_content: if group in poetry_content["group"]: - removed = self._remove_packages( - packages, - [], - poetry_content["group"][group].get("dependencies", {}), - group, + removed.update( + self._remove_packages( + packages=packages, + standard_section=[], + poetry_section=poetry_content["group"][group].get( + "dependencies", {} + ), + group_name=group, + ) ) if not poetry_content["group"][group]: del poetry_content["group"][group] + if group in groups_content: + removed.update( + self._remove_packages( + packages=packages, + standard_section=groups_content[group], + poetry_section={}, + group_name=group, + ) + ) + if not groups_content[group]: + del groups_content[group] if "group" in poetry_content and not poetry_content["group"]: del poetry_content["group"] + if "dependency-groups" in content and not content["dependency-groups"]: + del content["dependency-groups"] not_found = set(packages).difference(removed) if not_found: @@ -138,7 +174,7 @@ def handle(self) -> int: def _remove_packages( self, packages: list[str], - project_section: list[str], + standard_section: list[str], poetry_section: dict[str, Any], group_name: str, ) -> set[str]: @@ -147,9 +183,9 @@ def _remove_packages( for package in packages: normalized_name = canonicalize_name(package) - for requirement in project_section.copy(): + for requirement in standard_section.copy(): if Dependency.create_from_pep_508(requirement).name == normalized_name: - project_section.remove(requirement) + standard_section.remove(requirement) removed.add(package) for existing_package in list(poetry_section): if canonicalize_name(existing_package) == normalized_name: diff --git a/src/poetry/console/commands/self/self_command.py b/src/poetry/console/commands/self/self_command.py index 316fd3ec5f9..04f45902ec7 100644 --- a/src/poetry/console/commands/self/self_command.py +++ b/src/poetry/console/commands/self/self_command.py @@ -1,7 +1,10 @@ from __future__ import annotations +import typing + from pathlib import Path from typing import TYPE_CHECKING +from typing import Any from packaging.utils import canonicalize_name from poetry.core.packages.dependency import Dependency @@ -62,25 +65,35 @@ def activated_groups(self) -> set[NormalizedName]: def generate_system_pyproject(self) -> None: preserved = {} + preserved_groups: dict[str, Any] = {} if self.system_pyproject.exists(): - content = PyProjectTOML(self.system_pyproject).poetry_config + toml_file = PyProjectTOML(self.system_pyproject) + content = toml_file.data for key in {"group", "source"}: - if key in content: - preserved[key] = content[key] + if key in toml_file.poetry_config: + preserved[key] = toml_file.poetry_config[key] + + if "dependency-groups" in content: + preserved_groups = typing.cast( + "dict[str, Any]", content["dependency-groups"] + ) package = ProjectPackage(name="poetry-instance", version=__version__) package.add_dependency(Dependency(name="poetry", constraint=f"{__version__}")) package.python_versions = ".".join(str(v) for v in self.env.version_info[:3]) - content = Factory.create_pyproject_from_package(package=package) + content = Factory.create_legacy_pyproject_from_package(package=package) content["tool"]["poetry"]["package-mode"] = False # type: ignore[index] for key in preserved: content["tool"]["poetry"][key] = preserved[key] # type: ignore[index] + if preserved_groups: + content["dependency-groups"] = preserved_groups + pyproject = PyProjectTOML(self.system_pyproject) pyproject.file.write(content) diff --git a/src/poetry/factory.py b/src/poetry/factory.py index 6e6e66700e7..2a76e1526cd 100644 --- a/src/poetry/factory.py +++ b/src/poetry/factory.py @@ -220,7 +220,7 @@ def create_package_source( ) @classmethod - def create_pyproject_from_package(cls, package: Package) -> TOMLDocument: + def create_legacy_pyproject_from_package(cls, package: Package) -> TOMLDocument: import tomlkit from poetry.utils.dependency_specification import dependency_to_specification diff --git a/src/poetry/layouts/layout.py b/src/poetry/layouts/layout.py index 18f72e903ea..6dca13aba21 100644 --- a/src/poetry/layouts/layout.py +++ b/src/poetry/layouts/layout.py @@ -38,10 +38,12 @@ dependencies = [ ] +[dependency-groups] +dev = [ +] + [tool.poetry] packages = [] - -[tool.poetry.group.dev.dependencies] """ poetry_core_version = Version.parse(importlib.metadata.version("poetry-core")) @@ -179,11 +181,10 @@ def generate_project_content(self) -> TOMLDocument: if self._dev_dependencies: for dep_name, dep_constraint in self._dev_dependencies.items(): - poetry_content["group"]["dev"]["dependencies"][dep_name] = ( - dep_constraint - ) + dependency = Factory.create_dependency(dep_name, dep_constraint) + content["dependency-groups"]["dev"].append(dependency.to_pep_508()) else: - del poetry_content["group"] + del content["dependency-groups"] if not poetry_content: del content["tool"]["poetry"] diff --git a/tests/console/commands/self/test_add_plugins.py b/tests/console/commands/self/test_add_plugins.py index 7687a7b8785..bfbed48d016 100644 --- a/tests/console/commands/self/test_add_plugins.py +++ b/tests/console/commands/self/test_add_plugins.py @@ -1,11 +1,6 @@ from __future__ import annotations from typing import TYPE_CHECKING -from typing import Any - - -if TYPE_CHECKING: - from collections.abc import Mapping import pytest @@ -32,13 +27,14 @@ def tester(command_tester_factory: CommandTesterFactory) -> CommandTester: def assert_plugin_add_result( tester: CommandTester, expected: str, - constraint: str | Mapping[str, str | list[str]], + constraint: str, ) -> None: assert tester.io.fetch_output() == expected - dependencies: dict[str, Any] = get_self_command_dependencies() + dependencies: list[str] | None = get_self_command_dependencies() - assert "poetry-plugin" in dependencies - assert dependencies["poetry-plugin"] == constraint + assert dependencies + assert "poetry-plugin" in dependencies[0] + assert constraint in dependencies[0] def test_add_no_constraint( @@ -61,7 +57,7 @@ def test_add_no_constraint( Writing lock file """ - assert_plugin_add_result(tester, expected, "^0.1.0") + assert_plugin_add_result(tester, expected, "(>=0.1.0,<0.2.0)") def test_add_with_constraint( @@ -84,7 +80,7 @@ def test_add_with_constraint( Writing lock file """ - assert_plugin_add_result(tester, expected, "^0.2.0") + assert_plugin_add_result(tester, expected, "(>=0.2.0,<0.3.0)") def test_add_with_git_constraint( @@ -108,7 +104,7 @@ def test_add_with_git_constraint( """ assert_plugin_add_result( - tester, expected, {"git": "https://github.com/demo/poetry-plugin.git"} + tester, expected, "https://github.com/demo/poetry-plugin.git" ) @@ -134,11 +130,11 @@ def test_add_with_git_constraint_with_extras( Writing lock file """ - constraint: dict[str, str | list[str]] = { - "git": "https://github.com/demo/poetry-plugin.git", - "extras": ["foo"], - } - assert_plugin_add_result(tester, expected, constraint) + assert_plugin_add_result( + tester, + expected, + "poetry-plugin[foo] @ git+https://github.com/demo/poetry-plugin.git", + ) @pytest.mark.parametrize( @@ -173,19 +169,7 @@ def test_add_with_git_constraint_with_subdirectory( Writing lock file """ - constraint = { - "git": "https://github.com/demo/poetry-plugin2.git", - "subdirectory": "subdir", - } - - if rev: - constraint["rev"] = rev - - assert_plugin_add_result( - tester, - expected, - constraint, - ) + assert_plugin_add_result(tester, expected, url) def test_add_existing_plugin_warns_about_no_operation( @@ -248,8 +232,10 @@ def test_add_existing_plugin_updates_if_requested( [tool.poetry.dependencies] python = "^3.6" -[tool.poetry.group.{SelfCommand.ADDITIONAL_PACKAGE_GROUP}.dependencies] -poetry-plugin = "^1.2.3" +[dependency-groups] +{SelfCommand.ADDITIONAL_PACKAGE_GROUP} = [ + "poetry-plugin (>=1.2.3,<2.0.0)" +] """ ) @@ -273,7 +259,7 @@ def test_add_existing_plugin_updates_if_requested( Writing lock file """ - assert_plugin_add_result(tester, expected, "^2.3.4") + assert_plugin_add_result(tester, expected, "(>=2.3.4,<3.0.0)") def test_adding_a_plugin_can_update_poetry_dependencies_if_needed( @@ -310,4 +296,4 @@ def test_adding_a_plugin_can_update_poetry_dependencies_if_needed( Writing lock file """ - assert_plugin_add_result(tester, expected, "^1.2.3") + assert_plugin_add_result(tester, expected, "(>=1.2.3,<2.0.0)") diff --git a/tests/console/commands/self/test_remove_plugins.py b/tests/console/commands/self/test_remove_plugins.py index 6e525e78906..2e708725c8e 100644 --- a/tests/console/commands/self/test_remove_plugins.py +++ b/tests/console/commands/self/test_remove_plugins.py @@ -32,10 +32,15 @@ def install_plugin(installed: Repository) -> None: package = ProjectPackage("poetry-instance", __version__) plugin = Package("poetry-plugin", "1.2.3") - package.add_dependency( - Dependency(plugin.name, "^1.2.3", groups=[SelfCommand.ADDITIONAL_PACKAGE_GROUP]) + content = Factory.create_legacy_pyproject_from_package(package) + content["dependency-groups"] = tomlkit.table() + content["dependency-groups"][SelfCommand.ADDITIONAL_PACKAGE_GROUP] = tomlkit.array( # type: ignore[index] + "[\n]" ) - content = Factory.create_pyproject_from_package(package) + content["dependency-groups"][SelfCommand.ADDITIONAL_PACKAGE_GROUP].append( # type: ignore[index, union-attr, call-arg] + Dependency(plugin.name, "^1.2.3").to_pep_508() + ) + system_pyproject_file = SelfCommand.get_default_system_pyproject_file() with open(system_pyproject_file, "w", encoding="utf-8", newline="") as f: f.write(content.as_string()) @@ -81,7 +86,6 @@ def test_remove_installed_package(tester: CommandTester) -> None: dependencies = get_self_command_dependencies() - assert "poetry-plugin" not in dependencies assert not dependencies @@ -103,4 +107,6 @@ def test_remove_installed_package_dry_run(tester: CommandTester) -> None: dependencies = get_self_command_dependencies() - assert "poetry-plugin" in dependencies + assert dependencies + assert len(dependencies) == 1 + assert "poetry-plugin" in dependencies[0] diff --git a/tests/console/commands/self/test_self_command.py b/tests/console/commands/self/test_self_command.py index e38cee61873..b5cfe6ab829 100644 --- a/tests/console/commands/self/test_self_command.py +++ b/tests/console/commands/self/test_self_command.py @@ -19,7 +19,7 @@ def example_system_pyproject() -> str: package.add_dependency( Dependency(plugin.name, "^1.2.3", groups=[SelfCommand.ADDITIONAL_PACKAGE_GROUP]) ) - content = Factory.create_pyproject_from_package(package) + content = Factory.create_legacy_pyproject_from_package(package) return content.as_string().rstrip("\n") diff --git a/tests/console/commands/self/utils.py b/tests/console/commands/self/utils.py index 7a70bd3c011..28448914315 100644 --- a/tests/console/commands/self/utils.py +++ b/tests/console/commands/self/utils.py @@ -3,12 +3,12 @@ from pathlib import Path from typing import Any -from tomlkit.items import Table as TOMLTable +from tomlkit.items import Array from poetry.factory import Factory -def get_self_command_dependencies(locked: bool = True) -> TOMLTable: +def get_self_command_dependencies(locked: bool = True) -> Array | None: from poetry.console.commands.self.self_command import SelfCommand from poetry.locations import CONFIG_DIR @@ -23,14 +23,11 @@ def get_self_command_dependencies(locked: bool = True) -> TOMLTable: poetry = Factory().create_poetry(system_pyproject_file.parent, disable_plugins=True) pyproject: dict[str, Any] = poetry.file.read() - content = pyproject["tool"]["poetry"] + content = pyproject.get("dependency-groups", {}) - assert "group" in content - assert SelfCommand.ADDITIONAL_PACKAGE_GROUP in content["group"] - assert "dependencies" in content["group"][SelfCommand.ADDITIONAL_PACKAGE_GROUP] + if SelfCommand.ADDITIONAL_PACKAGE_GROUP not in content: + return None - dependencies = content["group"][SelfCommand.ADDITIONAL_PACKAGE_GROUP][ - "dependencies" - ] - assert isinstance(dependencies, TOMLTable) + dependencies = content[SelfCommand.ADDITIONAL_PACKAGE_GROUP] + assert isinstance(dependencies, Array) return dependencies diff --git a/tests/console/commands/test_add.py b/tests/console/commands/test_add.py index bd4dd1c4c2b..745c574fa0a 100644 --- a/tests/console/commands/test_add.py +++ b/tests/console/commands/test_add.py @@ -7,6 +7,7 @@ from typing import cast import pytest +import tomlkit from packaging.utils import canonicalize_name from poetry.core.constraints.version import Version @@ -595,6 +596,230 @@ def test_add_directory_constraint( assert content["dependencies"]["demo"] == expected_content +def test_add_to_new_group_keeps_existing_group( + app: PoetryTestApplication, tester: CommandTester +) -> None: + pyproject: dict[str, Any] = app.poetry.file.read() + groups_content: dict[str, Any] = tomlkit.parse( + """\ +[dependency-groups] +example = [ + "cachy (>=0.2.0,<0.3.0)", +] +""" + ) + pyproject["dependency-groups"] = groups_content["dependency-groups"] + pyproject = cast("TOMLDocument", pyproject) + app.poetry.file.write(pyproject) + + tester.execute("-G foo pendulum") + + expected = """\ +Using version ^1.4.4 for pendulum +""" + + assert tester.io.fetch_output().startswith(expected) + assert isinstance(tester.command, InstallerCommand) + assert tester.command.installer.executor.installations_count == 1 + + pyproject = app.poetry.file.read() + pyproject = cast("dict[str, Any]", pyproject) + assert "example" in pyproject["dependency-groups"] + assert pyproject["dependency-groups"]["example"] == [ + "cachy (>=0.2.0,<0.3.0)", + ] + assert pyproject["dependency-groups"]["foo"] == [ + "pendulum (>=1.4.4,<2.0.0)", + ] + + +@pytest.mark.parametrize("additional_poetry_group", [False, True]) +def test_add_to_existing_group( + app: PoetryTestApplication, tester: CommandTester, additional_poetry_group: bool +) -> None: + pyproject: dict[str, Any] = app.poetry.file.read() + groups_content: dict[str, Any] = tomlkit.parse( + """\ +[dependency-groups] +example = [ + "cachy (>=0.2.0,<0.3.0)", +] +""" + ) + pyproject["dependency-groups"] = groups_content["dependency-groups"] + if additional_poetry_group: + poetry_groups_content: dict[str, Any] = tomlkit.parse( + """\ +[tool.poetry.group.example.dependencies] +cachy = { allow-prereleases = true } +""" + ) + pyproject["tool"]["poetry"]["group"] = poetry_groups_content["tool"]["poetry"][ + "group" + ] + pyproject = cast("TOMLDocument", pyproject) + app.poetry.file.write(pyproject) + + tester.execute("-G example pendulum") + + expected = """\ +Using version ^1.4.4 for pendulum +""" + + assert tester.io.fetch_output().startswith(expected) + assert isinstance(tester.command, InstallerCommand) + assert tester.command.installer.executor.installations_count == 1 + + pyproject = app.poetry.file.read() + pyproject = cast("dict[str, Any]", pyproject) + assert "example" in pyproject["dependency-groups"] + assert pyproject["dependency-groups"]["example"] == [ + "cachy (>=0.2.0,<0.3.0)", + "pendulum (>=1.4.4,<2.0.0)", + ] + if additional_poetry_group: + assert "example" in pyproject["tool"]["poetry"]["group"] + assert pyproject["tool"]["poetry"]["group"]["example"]["dependencies"] == { + "cachy": {"allow-prereleases": True}, + } + else: + assert "group" not in pyproject["tool"]["poetry"] + + +def test_add_to_group_with_latest_overwrite_existing( + app: PoetryTestApplication, tester: CommandTester +) -> None: + pyproject: dict[str, Any] = app.poetry.file.read() + groups_content: dict[str, Any] = tomlkit.parse( + """\ +[dependency-groups] +example = [ + "cachy (>=0.1.0,<0.2.0)", + "pendulum (>=1.4.4,<2.0.0)", +] +""" + ) + pyproject["dependency-groups"] = groups_content["dependency-groups"] + pyproject = cast("TOMLDocument", pyproject) + app.poetry.file.write(pyproject) + + tester.execute("-G example cachy@latest") + + expected = """\ +Using version ^0.2.0 for cachy +""" + + assert tester.io.fetch_output().startswith(expected) + assert isinstance(tester.command, InstallerCommand) + # `cachy` has `msgpack-python` as dependency. So installation count increases by 1. + assert tester.command.installer.executor.installations_count == 2 + + pyproject = app.poetry.file.read() + pyproject = cast("dict[str, Any]", pyproject) + assert "example" in pyproject["dependency-groups"] + assert pyproject["dependency-groups"]["example"] == [ + "cachy (>=0.2.0,<0.3.0)", + "pendulum (>=1.4.4,<2.0.0)", + ] + + +def test_add_multiple_dependencies_to_dependency_group( + app: PoetryTestApplication, tester: CommandTester +) -> None: + tester.execute("-G example cachy pendulum") + + expected = """\ +Using version ^0.2.0 for cachy +Using version ^1.4.4 for pendulum +""" + + assert tester.io.fetch_output().startswith(expected) + + pyproject: dict[str, Any] = app.poetry.file.read() + assert isinstance(tester.command, InstallerCommand) + # `cachy` has `msgpack-python` as dependency. So installation count increases by 1. + assert tester.command.installer.executor.installations_count == 3 + + assert "example" in pyproject["dependency-groups"] + assert pyproject["dependency-groups"]["example"] == [ + "cachy (>=0.2.0,<0.3.0)", + "pendulum (>=1.4.4,<2.0.0)", + ] + + +def test_add_to_group_uses_existing_legacy_group( + app: PoetryTestApplication, tester: CommandTester +) -> None: + pyproject: dict[str, Any] = app.poetry.file.read() + groups_content: dict[str, Any] = tomlkit.parse( + """\ +[tool.poetry.group.example.dependencies] +pendulum = "^1.4.4" +""" + ) + pyproject["tool"]["poetry"]["group"] = groups_content["tool"]["poetry"]["group"] + + pyproject = cast("TOMLDocument", pyproject) + app.poetry.file.write(pyproject) + + tester.execute("-G example cachy") + + expected = """\ +Using version ^0.2.0 for cachy +""" + + assert tester.io.fetch_output().startswith(expected) + assert isinstance(tester.command, InstallerCommand) + # `cachy` has `msgpack-python` as dependency. So installation count increases by 1. + assert tester.command.installer.executor.installations_count == 2 + + pyproject = app.poetry.file.read() + pyproject = cast("dict[str, Any]", pyproject) + assert "dependency-groups" not in pyproject + assert "example" in pyproject["tool"]["poetry"]["group"] + assert "pendulum" in pyproject["tool"]["poetry"]["group"]["example"]["dependencies"] + assert "cachy" in pyproject["tool"]["poetry"]["group"]["example"]["dependencies"] + + +@pytest.mark.parametrize( + "required_fixtures", + [["git/github.com/demo/demo"]], +) +def test_add_group_directory_constraint_mix_pep735( + app: PoetryTestApplication, + tester: CommandTester, +) -> None: + path = "../git/github.com/demo/demo" + tester.execute(f"-G example -e {path}") + + demo_path = app.poetry.file.path.parent.joinpath(path).resolve().as_posix() + expected = f"""\ + +Updating dependencies +Resolving dependencies... + +Package operations: 2 installs, 0 updates, 0 removals + + - Installing pendulum (1.4.4) + - Installing demo (0.1.2 {demo_path}) + +Writing lock file +""" + + assert tester.io.fetch_output() == expected + assert isinstance(tester.command, InstallerCommand) + assert tester.command.installer.executor.installations_count == 2 + + pyproject: dict[str, Any] = app.poetry.file.read() + + assert "demo @ file://" in pyproject["dependency-groups"]["example"][0] + assert demo_path in pyproject["dependency-groups"]["example"][0] + assert "demo" in pyproject["tool"]["poetry"]["group"]["example"]["dependencies"] + assert pyproject["tool"]["poetry"]["group"]["example"]["dependencies"]["demo"] == { + "develop": True + } + + @pytest.mark.parametrize( "required_fixtures", [["git/github.com/demo/pyproject-demo"]], @@ -1078,17 +1303,15 @@ def test_add_to_section_that_does_not_exist_yet( assert tester.command.installer.executor.installations_count == 2 pyproject: dict[str, Any] = app.poetry.file.read() - content = pyproject["tool"]["poetry"] + content = pyproject["dependency-groups"] - assert "cachy" in content["group"][group_name]["dependencies"] - assert content["group"][group_name]["dependencies"]["cachy"] == "^0.2.0" + assert content[group_name][0] == "cachy (>=0.2.0,<0.3.0)" escaped_group_name = f'"{group_name}"' if "." in group_name else group_name expected = f"""\ - -[tool.poetry.group.{escaped_group_name}.dependencies] -cachy = "^0.2.0" - +{escaped_group_name} = [ + "cachy (>=0.2.0,<0.3.0)" +] """ string_content = content.as_string() if "\r\n" in string_content: @@ -1118,15 +1341,14 @@ def test_add_creating_poetry_section_does_not_remove_existing_tools( assert tester.command.installer.executor.installations_count == 2 pyproject: dict[str, Any] = poetry.file.read() - content = pyproject["tool"]["poetry"] + content = pyproject["dependency-groups"] - assert "cachy" in content["group"]["dev"]["dependencies"] - assert content["group"]["dev"]["dependencies"]["cachy"] == "^0.2.0" + assert content["dev"][0] == "cachy (>=0.2.0,<0.3.0)" assert "foo" in pyproject["tool"] assert pyproject["tool"]["foo"]["key"] == "value" -def test_add_to_dev_section(app: PoetryTestApplication, tester: CommandTester) -> None: +def test_add_to_dev_group(app: PoetryTestApplication, tester: CommandTester) -> None: tester.execute("cachy --dev") expected = """\ @@ -1149,10 +1371,9 @@ def test_add_to_dev_section(app: PoetryTestApplication, tester: CommandTester) - assert tester.command.installer.executor.installations_count == 2 pyproject: dict[str, Any] = app.poetry.file.read() - content = pyproject["tool"]["poetry"] + content = pyproject["dependency-groups"] - assert "cachy" in content["group"]["dev"]["dependencies"] - assert content["group"]["dev"]["dependencies"]["cachy"] == "^0.2.0" + assert content["dev"][0] == "cachy (>=0.2.0,<0.3.0)" def test_add_should_not_select_prereleases( diff --git a/tests/console/commands/test_init.py b/tests/console/commands/test_init.py index 98222c385ac..8c9338eb6e3 100644 --- a/tests/console/commands/test_init.py +++ b/tests/console/commands/test_init.py @@ -153,10 +153,11 @@ def test_interactive_with_dependencies( "flask (>=2.0.0,<3.0.0)" ] -[tool.poetry] +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)" +] -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" [build-system] requires = ["poetry-core>=2.0.0,<3.0.0"] @@ -278,10 +279,10 @@ def test_interactive_with_git_dependencies( "demo @ git+https://github.com/demo/demo.git" ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)" +] """ assert expected in tester.io.fetch_output() @@ -374,10 +375,10 @@ def test_interactive_with_git_dependencies_with_reference( "demo @ git+https://github.com/demo/demo.git@develop" ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)" +] """ assert expected in tester.io.fetch_output() @@ -423,10 +424,10 @@ def test_interactive_with_git_dependencies_and_other_name( "demo @ git+https://github.com/demo/pyproject-demo.git" ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)" +] """ assert expected in tester.io.fetch_output() @@ -479,10 +480,10 @@ def test_interactive_with_directory_dependency( "demo @ {demo_uri}" ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)" +] """ assert expected in tester.io.fetch_output() @@ -534,10 +535,10 @@ def test_interactive_with_directory_dependency_and_other_name( "demo @ {demo_uri}" ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)" +] """ assert expected in tester.io.fetch_output() @@ -590,10 +591,10 @@ def test_interactive_with_file_dependency( "demo @ {demo_uri}" ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)" +] """ assert expected in tester.io.fetch_output() @@ -639,10 +640,10 @@ def test_interactive_with_wrong_dependency_inputs( "pendulum (>=2.0.0,<3.0.0)" ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "3.6.0" +[dependency-groups] +dev = [ + "pytest (==3.6.0)" +] """ assert expected in tester.io.fetch_output() @@ -786,10 +787,10 @@ def test_predefined_dev_dependency(tester: CommandTester, repo: TestRepository) dependencies = [ ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)" +] """ assert expected in tester.io.fetch_output() @@ -833,17 +834,15 @@ def test_predefined_and_interactive_dev_dependencies( dependencies = [ ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" -pytest-requests = "^0.2.0" +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)", + "pytest-requests (>=0.2.0,<0.3.0)" +] """ output = tester.io.fetch_output() assert expected in output - assert 'pytest-requests = "^0.2.0"' in output - assert 'pytest = "^3.6.0"' in output def test_predefined_all_options(tester: CommandTester, repo: TestRepository) -> None: @@ -884,10 +883,10 @@ def test_predefined_all_options(tester: CommandTester, repo: TestRepository) -> "pendulum (>=2.0.0,<3.0.0)" ] -[tool.poetry] - -[tool.poetry.group.dev.dependencies] -pytest = "^3.6.0" +[dependency-groups] +dev = [ + "pytest (>=3.6.0,<4.0.0)" +] """ output = tester.io.fetch_output() diff --git a/tests/console/commands/test_remove.py b/tests/console/commands/test_remove.py index 59730c544b3..dda95ca0843 100644 --- a/tests/console/commands/test_remove.py +++ b/tests/console/commands/test_remove.py @@ -129,7 +129,87 @@ def test_remove_from_project_and_poetry( assert expected_poetry_string in string_content +def test_remove_from_pep735_group_and_poetry_group( + tester: CommandTester, + app: PoetryTestApplication, + repo: TestRepository, + installed: Repository, +) -> None: + repo.add_package(Package("foo", "2.0.0")) + repo.add_package(Package("bar", "1.0.0")) + + pyproject: dict[str, Any] = app.poetry.file.read() + + pep735_dependencies: dict[str, Any] = tomlkit.parse( + """\ +[dependency-groups] +dev = [ + "foo>=2.0", + "bar>=1.0", +] +""" + ) + + poetry_dependencies: dict[str, Any] = tomlkit.parse( + """\ +[tool.poetry.group.dev.dependencies] +foo = "^2.0.0" +bar = "^1.0.0" + +""" + ) + + pyproject["dependency-groups"] = pep735_dependencies["dependency-groups"] + pyproject["tool"]["poetry"]["group"] = poetry_dependencies["tool"]["poetry"][ + "group" + ] + pyproject = cast("TOMLDocument", pyproject) + app.poetry.file.write(pyproject) + + app.poetry.package.add_dependency( + Factory.create_dependency("foo", "^2.0.0", groups=["dev"]) + ) + app.poetry.package.add_dependency( + Factory.create_dependency("bar", "^1.0.0", groups=["dev"]) + ) + + tester.execute("foo") + + pyproject = app.poetry.file.read() + pyproject = cast("dict[str, Any]", pyproject) + pep735_dependencies = pyproject["dependency-groups"]["dev"] + assert "foo>=2.0" not in pep735_dependencies + assert "bar>=1.0" in pep735_dependencies + poetry_dependencies = pyproject["tool"]["poetry"]["group"]["dev"]["dependencies"] + assert "foo" not in poetry_dependencies + assert "bar" in poetry_dependencies + + expected_pep735_string = """\ +[dependency-groups] +dev = [ + "bar>=1.0", +] +""" + expected_poetry_string = """\ + +[tool.poetry.group.dev.dependencies] +bar = "^1.0.0" + +""" + pyproject = cast("TOMLDocument", pyproject) + string_content = pyproject.as_string() + if "\r\n" in string_content: + # consistent line endings + expected_pep735_string = expected_pep735_string.replace("\n", "\r\n") + expected_poetry_string = expected_poetry_string.replace("\n", "\r\n") + + assert expected_pep735_string in string_content + assert expected_poetry_string in string_content + + +@pytest.mark.parametrize("pep_735", [True, False]) def test_remove_without_specific_group_removes_from_all_groups( + pep_735: bool, tester: CommandTester, app: PoetryTestApplication, repo: TestRepository, @@ -143,17 +223,32 @@ def test_remove_without_specific_group_removes_from_all_groups( repo.add_package(Package("baz", "1.0.0")) pyproject: dict[str, Any] = app.poetry.file.read() + pyproject["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0" - groups_content: dict[str, Any] = tomlkit.parse( - """\ + if pep_735: + groups_content: dict[str, Any] = tomlkit.parse( + """\ +[dependency-groups] +bar = [ + "foo (>=2.0,<3.0)", + "baz (>=1.0,<2.0)", +] +""" + ) + pyproject["dependency-groups"] = groups_content["dependency-groups"] + + else: + groups_content = tomlkit.parse( + """\ [tool.poetry.group.bar.dependencies] foo = "^2.0.0" baz = "^1.0.0" """ - ) - pyproject["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0" - pyproject["tool"]["poetry"]["group"] = groups_content["tool"]["poetry"]["group"] + ) + groups_content = cast("dict[str, Any]", groups_content) + pyproject["tool"]["poetry"]["group"] = groups_content["tool"]["poetry"]["group"] + pyproject = cast("TOMLDocument", pyproject) app.poetry.file.write(pyproject) @@ -171,14 +266,23 @@ def test_remove_without_specific_group_removes_from_all_groups( pyproject = cast("dict[str, Any]", pyproject) content = pyproject["tool"]["poetry"] assert "foo" not in content["dependencies"] - assert "foo" not in content["group"]["bar"]["dependencies"] - assert "baz" in content["group"]["bar"]["dependencies"] - expected = """\ + if pep_735: + assert not any("foo" in dep for dep in pyproject["dependency-groups"]["bar"]) + assert any("baz" in dep for dep in pyproject["dependency-groups"]["bar"]) + expected = """\ +[dependency-groups] +bar = [ + "baz (>=1.0,<2.0)", +] +""" + else: + assert "foo" not in content["group"]["bar"]["dependencies"] + assert "baz" in content["group"]["bar"]["dependencies"] + expected = """\ [tool.poetry.group.bar.dependencies] baz = "^1.0.0" - """ pyproject = cast("TOMLDocument", pyproject) string_content = pyproject.as_string() @@ -189,7 +293,9 @@ def test_remove_without_specific_group_removes_from_all_groups( assert expected in string_content +@pytest.mark.parametrize("pep_735", [True, False]) def test_remove_with_specific_group_removes_from_specific_groups( + pep_735: bool, tester: CommandTester, app: PoetryTestApplication, repo: TestRepository, @@ -203,17 +309,31 @@ def test_remove_with_specific_group_removes_from_specific_groups( repo.add_package(Package("baz", "1.0.0")) pyproject: dict[str, Any] = app.poetry.file.read() + pyproject["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0" - groups_content: dict[str, Any] = tomlkit.parse( - """\ + if pep_735: + groups_content: dict[str, Any] = tomlkit.parse( + """\ +[dependency-groups] +bar = [ + "foo (>=2.0,<3.0)", + "baz (>=1.0,<2.0)", +] + """ + ) + pyproject["dependency-groups"] = groups_content["dependency-groups"] + + else: + groups_content = tomlkit.parse( + """\ [tool.poetry.group.bar.dependencies] foo = "^2.0.0" baz = "^1.0.0" + """ + ) + groups_content = cast("dict[str, Any]", groups_content) + pyproject["tool"]["poetry"]["group"] = groups_content["tool"]["poetry"]["group"] -""" - ) - pyproject["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0" - pyproject["tool"]["poetry"]["group"] = groups_content["tool"]["poetry"]["group"] pyproject = cast("TOMLDocument", pyproject) app.poetry.file.write(pyproject) @@ -231,16 +351,26 @@ def test_remove_with_specific_group_removes_from_specific_groups( pyproject = cast("dict[str, Any]", pyproject) content = pyproject["tool"]["poetry"] assert "foo" in content["dependencies"] - assert "foo" not in content["group"]["bar"]["dependencies"] - assert "baz" in content["group"]["bar"]["dependencies"] - expected = """\ + if pep_735: + assert not any("foo" in dep for dep in pyproject["dependency-groups"]["bar"]) + assert any("baz" in dep for dep in pyproject["dependency-groups"]["bar"]) + expected = """\ +[dependency-groups] +bar = [ + "baz (>=1.0,<2.0)", +] +""" + else: + assert "foo" not in content["group"]["bar"]["dependencies"] + assert "baz" in content["group"]["bar"]["dependencies"] + expected = """\ [tool.poetry.group.bar.dependencies] baz = "^1.0.0" - """ - string_content = content.as_string() + pyproject = cast("TOMLDocument", pyproject) + string_content = pyproject.as_string() if "\r\n" in string_content: # consistent line endings expected = expected.replace("\n", "\r\n") @@ -248,7 +378,9 @@ def test_remove_with_specific_group_removes_from_specific_groups( assert expected in string_content +@pytest.mark.parametrize("pep_735", [True, False]) def test_remove_does_not_keep_empty_groups( + pep_735: bool, tester: CommandTester, app: PoetryTestApplication, repo: TestRepository, @@ -261,20 +393,33 @@ def test_remove_does_not_keep_empty_groups( repo.add_package(Package("foo", "2.0.0")) repo.add_package(Package("baz", "1.0.0")) - content: dict[str, Any] = app.poetry.file.read() + pyproject: dict[str, Any] = app.poetry.file.read() + pyproject["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0" - groups_content: dict[str, Any] = tomlkit.parse( - """\ + if pep_735: + groups_content: dict[str, Any] = tomlkit.parse( + """\ +[dependency-groups] +bar = [ + "foo (>=2.0,<3.0)", + "baz (>=1.0,<2.0)", +] + """ + ) + pyproject["dependency-groups"] = groups_content["dependency-groups"] + else: + groups_content = tomlkit.parse( + """\ [tool.poetry.group.bar.dependencies] foo = "^2.0.0" baz = "^1.0.0" """ - ) - content["tool"]["poetry"]["dependencies"]["foo"] = "^2.0.0" - content["tool"]["poetry"]["group"] = groups_content["tool"]["poetry"]["group"] - content = cast("TOMLDocument", content) - app.poetry.file.write(content) + ) + groups_content = cast("dict[str, Any]", groups_content) + pyproject["tool"]["poetry"]["group"] = groups_content["tool"]["poetry"]["group"] + pyproject = cast("TOMLDocument", pyproject) + app.poetry.file.write(pyproject) app.poetry.package.add_dependency(Factory.create_dependency("foo", "^2.0.0")) app.poetry.package.add_dependency( @@ -286,17 +431,26 @@ def test_remove_does_not_keep_empty_groups( tester.execute("foo baz --group bar") - pyproject: dict[str, Any] = app.poetry.file.read() + pyproject = app.poetry.file.read() + pyproject = cast("dict[str, Any]", pyproject) content = pyproject["tool"]["poetry"] + assert "foo" in content["dependencies"] - assert "foo" not in content["group"]["bar"]["dependencies"] - assert "baz" not in content["group"]["bar"]["dependencies"] - content = cast("TOMLDocument", content) - assert "[tool.poetry.group.bar]" not in content.as_string() - assert "[tool.poetry.group]" not in content.as_string() + + if pep_735: + assert "bar" not in pyproject.get("dependency-groups", {}) + assert "dependency-groups" not in pyproject + else: + assert "foo" not in content["group"]["bar"]["dependencies"] + assert "baz" not in content["group"]["bar"]["dependencies"] + content = cast("TOMLDocument", content) + assert "[tool.poetry.group.bar]" not in content.as_string() + assert "[tool.poetry.group]" not in content.as_string() +@pytest.mark.parametrize("pep_735", [True, False]) def test_remove_canonicalized_named_removes_dependency_correctly( + pep_735: bool, tester: CommandTester, app: PoetryTestApplication, repo: TestRepository, @@ -310,19 +464,32 @@ def test_remove_canonicalized_named_removes_dependency_correctly( repo.add_package(Package("baz", "1.0.0")) pyproject: dict[str, Any] = app.poetry.file.read() + pyproject["tool"]["poetry"]["dependencies"]["foo-bar"] = "^2.0.0" - groups_content: dict[str, Any] = tomlkit.parse( - """\ + if pep_735: + groups_content: dict[str, Any] = tomlkit.parse( + """\ +[dependency-groups] +bar = [ + "foo-bar (>=2.0,<3.0)", + "baz (>=1.0,<2.0)", +] +""" + ) + pyproject["dependency-groups"] = groups_content["dependency-groups"] + else: + groups_content = tomlkit.parse( + """\ [tool.poetry.group.bar.dependencies] foo-bar = "^2.0.0" baz = "^1.0.0" """ - ) - pyproject["tool"]["poetry"]["dependencies"]["foo-bar"] = "^2.0.0" - pyproject["tool"]["poetry"].value._insert_after( - "dependencies", "group", groups_content["tool"]["poetry"]["group"] - ) + ) + groups_content = cast("dict[str, Any]", groups_content) + pyproject["tool"]["poetry"].value._insert_after( + "dependencies", "group", groups_content["tool"]["poetry"]["group"] + ) pyproject = cast("TOMLDocument", pyproject) app.poetry.file.write(pyproject) @@ -339,15 +506,25 @@ def test_remove_canonicalized_named_removes_dependency_correctly( pyproject = app.poetry.file.read() pyproject = cast("dict[str, Any]", pyproject) content = pyproject["tool"]["poetry"] + assert "foo-bar" not in content["dependencies"] - assert "foo-bar" not in content["group"]["bar"]["dependencies"] - assert "baz" in content["group"]["bar"]["dependencies"] - expected = """\ + if pep_735: + assert not any("foo" in dep for dep in pyproject["dependency-groups"]["bar"]) + assert any("baz" in dep for dep in pyproject["dependency-groups"]["bar"]) + expected = """\ +[dependency-groups] +bar = [ + "baz (>=1.0,<2.0)", +] +""" + else: + assert "foo-bar" not in content["group"]["bar"]["dependencies"] + assert "baz" in content["group"]["bar"]["dependencies"] + expected = """\ [tool.poetry.group.bar.dependencies] baz = "^1.0.0" - """ pyproject = cast("TOMLDocument", pyproject) string_content = pyproject.as_string() diff --git a/tests/test_factory.py b/tests/test_factory.py index 9a07330d3db..68cdbb3a71e 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -164,7 +164,7 @@ def test_create_pyproject_from_package( poetry = Factory().create_poetry(fixture_dir(project)) package = poetry.package - pyproject: dict[str, Any] = Factory.create_pyproject_from_package(package) + pyproject: dict[str, Any] = Factory.create_legacy_pyproject_from_package(package) result = pyproject["tool"]["poetry"] expected = poetry.pyproject.poetry_config