Skip to content

Commit

Permalink
fix poetry add --optional locking
Browse files Browse the repository at this point in the history
  • Loading branch information
radoering committed Jan 19, 2025
1 parent 77cd259 commit 2eefadd
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 18 deletions.
24 changes: 24 additions & 0 deletions src/poetry/console/commands/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,13 @@ def handle(self) -> int:
else:
poetry_section[constraint_name] = poetry_constraint

if optional:
extra_name = canonicalize_name(optional)
# _in_extras must be set after converting the dependency to PEP 508
# and adding it to the project section to avoid a redundant extra marker
dependency._in_extras = [extra_name]
self._add_dependency_to_extras(dependency, extra_name)

# Refresh the locker
if project_section:
assert group == MAIN_GROUP
Expand Down Expand Up @@ -409,3 +416,20 @@ def notify_about_existing_packages(self, existing_packages: list[str]) -> None:
for name in existing_packages:
self.line(f" - <c1>{name}</c1>")
self.line(self._hint_update_packages)

def _add_dependency_to_extras(
self, dependency: Dependency, extra_name: NormalizedName
) -> None:
extras = dict(self.poetry.package.extras)
extra_deps = []
replaced = False
for dep in extras.get(extra_name, ()):
if dep.name == dependency.name:
extra_deps.append(dependency)
replaced = True
else:
extra_deps.append(dep)
if not replaced:
extra_deps.append(dependency)
extras[extra_name] = extra_deps
self.poetry.package.extras = extras
50 changes: 32 additions & 18 deletions tests/console/commands/test_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -822,13 +822,16 @@ def test_add_url_constraint_wheel_with_extras(
[
(None, {"my-extra": ["cachy (==0.2.0)"]}),
(
{"other": ["foo>2"]},
{"other": ["foo>2"], "my-extra": ["cachy (==0.2.0)"]},
{"other": ["tomlkit (<2)"]},
{"other": ["tomlkit (<2)"], "my-extra": ["cachy (==0.2.0)"]},
),
({"my-extra": ["foo>2"]}, {"my-extra": ["foo>2", "cachy (==0.2.0)"]}),
(
{"my-extra": ["foo>2", "cachy (==0.1.0)", "bar>1"]},
{"my-extra": ["foo>2", "cachy (==0.2.0)", "bar>1"]},
{"my-extra": ["tomlkit (<2)"]},
{"my-extra": ["tomlkit (<2)", "cachy (==0.2.0)"]},
),
(
{"my-extra": ["tomlkit (<2)", "cachy (==0.1.0)", "pendulum (>1)"]},
{"my-extra": ["tomlkit (<2)", "cachy (==0.2.0)", "pendulum (>1)"]},
),
],
)
Expand All @@ -841,29 +844,22 @@ def test_add_constraint_with_optional(
) -> None:
pyproject: dict[str, Any] = app.poetry.file.read()
if project_dependencies:
pyproject["project"]["dependencies"] = ["foo>1"]
pyproject["project"]["dependencies"] = ["tomlkit (<1)"]
if existing_extras:
pyproject["project"]["optional-dependencies"] = existing_extras
else:
pyproject["tool"]["poetry"]["dependencies"]["foo"] = "^1.0"
pyproject["tool"]["poetry"]["dependencies"]["tomlkit"] = "<1"
pyproject = cast("TOMLDocument", pyproject)
app.poetry.file.write(pyproject)
app.reset_poetry()

tester.execute("cachy=0.2.0 --optional my-extra")
expected = """\

Updating dependencies
Resolving dependencies...
No dependencies to install or update
Writing lock file
"""

assert tester.io.fetch_output() == expected
assert tester.io.fetch_output().endswith("Writing lock file\n")
assert isinstance(tester.command, InstallerCommand)
assert tester.command.installer.executor.installations_count == 0
assert tester.command.installer.executor.installations_count > 0

# check pyproject content
pyproject2: dict[str, Any] = app.poetry.file.read()
project_content = pyproject2["project"]
poetry_content = pyproject2["tool"]["poetry"]
Expand All @@ -887,6 +883,24 @@ def test_add_constraint_with_optional(
in tester.io.fetch_error()
)

# check lock content
if project_dependencies:
lock_data = app.poetry.locker.lock_data

extras = lock_data["extras"]
assert list(extras) == sorted(expected_extras)
assert extras["my-extra"] == sorted(
e.split(" ")[0] for e in expected_extras["my-extra"]
)

added_package: dict[str, Any] | None = None
for package in lock_data["package"]:
if package["name"] == "cachy":
added_package = package
break
assert added_package is not None
assert added_package.get("markers") == 'extra == "my-extra"'


def test_add_constraint_with_optional_not_main_group(
app: PoetryTestApplication, tester: CommandTester
Expand Down

0 comments on commit 2eefadd

Please sign in to comment.