diff --git a/src/poetry/repositories/link_sources/base.py b/src/poetry/repositories/link_sources/base.py index 30e1e5a751c..982467b8667 100644 --- a/src/poetry/repositories/link_sources/base.py +++ b/src/poetry/repositories/link_sources/base.py @@ -8,6 +8,7 @@ from typing import TYPE_CHECKING from typing import ClassVar +from packaging.utils import canonicalize_name from poetry.core.constraints.version import Version from poetry.core.packages.package import Package from poetry.core.version.exceptions import InvalidVersionError @@ -79,10 +80,18 @@ def links(self) -> Iterator[Link]: yield from links @classmethod - def link_package_data(cls, link: Link) -> Package | None: + def _link_package_name_and_version( + cls, link: Link + ) -> tuple[NormalizedName, Version] | None: + """Extract just the (normalized name, version) for a link. + + This is the hot path used when building the link cache: it avoids the + cost of constructing a full `Package` (which initializes a large + number of attributes) when only the name and version are needed as + cache keys. + """ name: str | None = None version_string: str | None = None - version: Version | None = None m = wheel_file_re.match(link.filename) or sdist_file_re.match(link.filename) if m: @@ -95,19 +104,29 @@ def link_package_data(cls, link: Link) -> Package | None: name = match.group(1) version_string = match.group(2) - if version_string: - try: - version = Version.parse(version_string) - except InvalidVersionError: - logger.debug( - "Skipping url (%s) due to invalid version (%s)", link.url, version - ) - return None - - pkg = None - if name and version: - pkg = Package(name, version, source_url=link.url) - return pkg + if not (name and version_string): + return None + + try: + version = Version.parse(version_string) + except InvalidVersionError: + logger.debug( + "Skipping url (%s) due to invalid version (%s)", + link.url, + version_string, + ) + return None + + return canonicalize_name(name), version + + @classmethod + def link_package_data(cls, link: Link) -> Package | None: + name_and_version = cls._link_package_name_and_version(link) + if name_and_version is None: + return None + + name, version = name_and_version + return Package(name, version, source_url=link.url) def links_for_version( self, name: NormalizedName, version: Version diff --git a/src/poetry/repositories/link_sources/html.py b/src/poetry/repositories/link_sources/html.py index 56907a6185e..e177dd57b12 100644 --- a/src/poetry/repositories/link_sources/html.py +++ b/src/poetry/repositories/link_sources/html.py @@ -60,9 +60,10 @@ def _link_cache(self) -> LinkCache: if link.ext not in self.SUPPORTED_FORMATS: continue - pkg = self.link_package_data(link) - if pkg: - links[pkg.name][pkg.version].append(link) + name_and_version = self._link_package_name_and_version(link) + if name_and_version: + name, version = name_and_version + links[name][version].append(link) return links diff --git a/src/poetry/repositories/link_sources/json.py b/src/poetry/repositories/link_sources/json.py index e6abb06ba18..7c362176219 100644 --- a/src/poetry/repositories/link_sources/json.py +++ b/src/poetry/repositories/link_sources/json.py @@ -61,9 +61,10 @@ def _link_cache(self) -> LinkCache: if link.ext not in self.SUPPORTED_FORMATS: continue - pkg = self.link_package_data(link) - if pkg: - links[pkg.name][pkg.version].append(link) + name_and_version = self._link_package_name_and_version(link) + if name_and_version: + name, version = name_and_version + links[name][version].append(link) return links