Skip to content

Commit 04c5cbf

Browse files
dimblebyradoering
authored andcommitted
canonicalized extra names (#6541)
(cherry picked from commit 44a89cb) Co-authored-by: Randy Döring <[email protected]>
1 parent 91b4522 commit 04c5cbf

File tree

16 files changed

+68
-63
lines changed

16 files changed

+68
-63
lines changed

poetry.lock

Lines changed: 13 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ generate-setup-file = false
4545
python = "^3.7"
4646

4747
poetry-core = "1.2.0"
48-
poetry-plugin-export = "^1.0.7"
48+
poetry-plugin-export = "^1.1.1"
4949
"backports.cached-property" = { version = "^1.0.2", python = "<3.8" }
5050
cachecontrol = { version = "^0.12.9", extras = ["filecache"] }
5151
cachy = "^0.3.0"
@@ -77,6 +77,8 @@ tox = "^3.18"
7777
pre-commit = "^2.6"
7878

7979
[tool.poetry.group.test.dependencies]
80+
# TODO: remove as soon as poetry-core with poetry-core#476 is available
81+
poetry-core = { git = "https://github.com/dimbleby/poetry-core.git", branch = "canonicalize-extras" }
8082
deepdiff = "^5.0"
8183
flatdict = "^4.0.1"
8284
httpretty = "^1.0"

src/poetry/console/commands/install.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ def handle(self) -> int:
115115
)
116116
return 1
117117

118+
extras: list[str]
118119
if self.option("all-extras"):
119120
extras = list(self.poetry.package.extras.keys())
120121
else:

src/poetry/installation/installer.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import TYPE_CHECKING
44

55
from cleo.io.null_io import NullIO
6+
from packaging.utils import NormalizedName
67
from packaging.utils import canonicalize_name
78

89
from poetry.installation.executor import Executor
@@ -63,7 +64,7 @@ def __init__(
6364

6465
self._whitelist: list[str] = []
6566

66-
self._extras: list[str] = []
67+
self._extras: list[NormalizedName] = []
6768

6869
if executor is None:
6970
executor = Executor(
@@ -175,7 +176,7 @@ def whitelist(self, packages: Iterable[str]) -> Installer:
175176
return self
176177

177178
def extras(self, extras: list[str]) -> Installer:
178-
self._extras = extras
179+
self._extras = [canonicalize_name(extra) for extra in extras]
179180

180181
return self
181182

@@ -259,8 +260,12 @@ def _do_install(self) -> int:
259260
"</warning>"
260261
)
261262

263+
locker_extras = {
264+
canonicalize_name(extra)
265+
for extra in self._locker.lock_data.get("extras", {})
266+
}
262267
for extra in self._extras:
263-
if extra not in self._locker.lock_data.get("extras", {}):
268+
if extra not in locker_extras:
264269
raise ValueError(f"Extra [{extra}] is not specified.")
265270

266271
# If we are installing from lock
@@ -547,11 +552,17 @@ def _get_extra_packages(self, repo: Repository) -> list[str]:
547552
548553
Maybe we just let the solver handle it?
549554
"""
550-
extras: dict[str, list[str]]
555+
extras: dict[NormalizedName, list[NormalizedName]]
551556
if self._update:
552557
extras = {k: [d.name for d in v] for k, v in self._package.extras.items()}
553558
else:
554-
extras = self._locker.lock_data.get("extras", {})
559+
raw_extras = self._locker.lock_data.get("extras", {})
560+
extras = {
561+
canonicalize_name(extra): [
562+
canonicalize_name(dependency) for dependency in dependencies
563+
]
564+
for extra, dependencies in raw_extras.items()
565+
}
555566

556567
return list(get_extra_package_names(repo.packages, extras, self._extras))
557568

src/poetry/packages/locker.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from typing import Any
1212
from typing import cast
1313

14+
from packaging.utils import canonicalize_name
1415
from poetry.core.packages.dependency import Dependency
1516
from poetry.core.packages.package import Package
1617
from poetry.core.semver.helpers import parse_constraint
@@ -157,6 +158,7 @@ def locked_repository(self) -> Repository:
157158
extras = info.get("extras", {})
158159
if extras:
159160
for name, deps in extras.items():
161+
name = canonicalize_name(name)
160162
package.extras[name] = []
161163

162164
for dep in deps:

src/poetry/puzzle/provider.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
from poetry.puzzle.exceptions import OverrideNeeded
3333
from poetry.repositories.exceptions import PackageNotFound
3434
from poetry.utils.helpers import download_file
35-
from poetry.utils.helpers import safe_extra
3635
from poetry.vcs.git import Git
3736

3837

@@ -563,7 +562,6 @@ def complete_package(
563562
# to the current package
564563
if dependency.extras:
565564
for extra in dependency.extras:
566-
extra = safe_extra(extra)
567565
if extra not in package.extras:
568566
continue
569567

@@ -590,9 +588,7 @@ def complete_package(
590588
(dep.is_optional() and dep.name not in optional_dependencies)
591589
or (
592590
dep.in_extras
593-
and not set(dep.in_extras).intersection(
594-
{safe_extra(extra) for extra in dependency.extras}
595-
)
591+
and not set(dep.in_extras).intersection(dependency.extras)
596592
)
597593
):
598594
continue

src/poetry/utils/extras.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
from typing import TYPE_CHECKING
4+
from typing import Collection
45

56

67
if TYPE_CHECKING:
@@ -15,9 +16,9 @@
1516

1617
def get_extra_package_names(
1718
packages: Sequence[Package],
18-
extras: Mapping[str, list[str]],
19-
extra_names: Sequence[str],
20-
) -> Iterable[str]:
19+
extras: Mapping[NormalizedName, Iterable[NormalizedName]],
20+
extra_names: Collection[NormalizedName],
21+
) -> Iterable[NormalizedName]:
2122
"""
2223
Returns all package names required by the given extras.
2324

src/poetry/utils/helpers.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import os
4-
import re
54
import shutil
65
import stat
76
import sys
@@ -152,18 +151,6 @@ def pluralize(count: int, word: str = "") -> str:
152151
return word + "s"
153152

154153

155-
def safe_extra(extra: str) -> str:
156-
"""Convert an arbitrary string to a standard 'extra' name.
157-
158-
Any runs of non-alphanumeric characters are replaced with a single '_',
159-
and the result is always lowercased.
160-
161-
See
162-
https://github.com/pypa/setuptools/blob/452e13c/pkg_resources/__init__.py#L1423-L1431.
163-
"""
164-
return re.sub("[^A-Za-z0-9.-]+", "_", extra).lower()
165-
166-
167154
def _get_win_folder_from_registry(csidl_name: str) -> str:
168155
if sys.platform != "win32":
169156
raise RuntimeError("Method can only be called on Windows.")

tests/console/commands/test_install.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,10 @@ def test_all_extras_populates_installer(tester: CommandTester, mocker: MockerFix
166166

167167
tester.execute("--all-extras")
168168

169-
assert tester.command.installer._extras == ["extras_a", "extras_b"]
169+
assert tester.command.installer._extras == ["extras-a", "extras-b"]
170170

171171

172-
def test_extras_conlicts_all_extras(tester: CommandTester, mocker: MockerFixture):
172+
def test_extras_conflicts_all_extras(tester: CommandTester, mocker: MockerFixture):
173173
"""
174174
The --extras doesn't make sense with --all-extras.
175175
"""

tests/installation/fixtures/with-dependencies-nested-extras.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ optional = false
77
python-versions = "*"
88

99
[package.dependencies]
10-
B = {version = "^1.0", optional = true, extras = ["C"]}
10+
B = {version = "^1.0", optional = true, extras = ["c"]}
1111

1212
[package.extras]
13-
b = ["B[C] (>=1.0,<2.0)"]
13+
b = ["B[c] (>=1.0,<2.0)"]
1414

1515
[[package]]
1616
name = "B"

0 commit comments

Comments
 (0)