Skip to content

Commit fee81fd

Browse files
committed
refactor: split off functions to get direct origin dependencies from provider (#7693)
1 parent 3248fe1 commit fee81fd

File tree

4 files changed

+122
-108
lines changed

4 files changed

+122
-108
lines changed

src/poetry/packages/direct_origin.py

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from __future__ import annotations
2+
3+
import functools
4+
import os
5+
import tempfile
6+
import urllib.parse
7+
8+
from pathlib import Path
9+
from typing import TYPE_CHECKING
10+
11+
from poetry.inspection.info import PackageInfo
12+
from poetry.inspection.info import PackageInfoError
13+
from poetry.utils.helpers import download_file
14+
from poetry.utils.helpers import get_file_hash
15+
from poetry.vcs.git import Git
16+
17+
18+
if TYPE_CHECKING:
19+
from poetry.core.packages.package import Package
20+
21+
22+
@functools.lru_cache(maxsize=None)
23+
def _get_package_from_git(
24+
url: str,
25+
branch: str | None = None,
26+
tag: str | None = None,
27+
rev: str | None = None,
28+
subdirectory: str | None = None,
29+
source_root: Path | None = None,
30+
) -> Package:
31+
source = Git.clone(
32+
url=url,
33+
source_root=source_root,
34+
branch=branch,
35+
tag=tag,
36+
revision=rev,
37+
clean=False,
38+
)
39+
revision = Git.get_revision(source)
40+
41+
path = Path(source.path)
42+
if subdirectory:
43+
path = path.joinpath(subdirectory)
44+
45+
package = DirectOrigin.get_package_from_directory(path)
46+
package._source_type = "git"
47+
package._source_url = url
48+
package._source_reference = rev or tag or branch or "HEAD"
49+
package._source_resolved_reference = revision
50+
package._source_subdirectory = subdirectory
51+
52+
return package
53+
54+
55+
class DirectOrigin:
56+
@classmethod
57+
def get_package_from_file(cls, file_path: Path) -> Package:
58+
try:
59+
package = PackageInfo.from_path(path=file_path).to_package(
60+
root_dir=file_path
61+
)
62+
except PackageInfoError:
63+
raise RuntimeError(
64+
f"Unable to determine package info from path: {file_path}"
65+
)
66+
67+
return package
68+
69+
@classmethod
70+
def get_package_from_directory(cls, directory: Path) -> Package:
71+
return PackageInfo.from_directory(path=directory).to_package(root_dir=directory)
72+
73+
@classmethod
74+
def get_package_from_url(cls, url: str) -> Package:
75+
file_name = os.path.basename(urllib.parse.urlparse(url).path)
76+
with tempfile.TemporaryDirectory() as temp_dir:
77+
dest = Path(temp_dir) / file_name
78+
download_file(url, dest)
79+
package = cls.get_package_from_file(dest)
80+
81+
package.files = [
82+
{"file": file_name, "hash": "sha256:" + get_file_hash(dest)}
83+
]
84+
85+
package._source_type = "url"
86+
package._source_url = url
87+
88+
return package
89+
90+
@staticmethod
91+
def get_package_from_vcs(
92+
vcs: str,
93+
url: str,
94+
branch: str | None = None,
95+
tag: str | None = None,
96+
rev: str | None = None,
97+
subdirectory: str | None = None,
98+
source_root: Path | None = None,
99+
) -> Package:
100+
if vcs != "git":
101+
raise ValueError(f"Unsupported VCS dependency {vcs}")
102+
103+
return _get_package_from_git(
104+
url=url,
105+
branch=branch,
106+
tag=tag,
107+
rev=rev,
108+
subdirectory=subdirectory,
109+
source_root=source_root,
110+
)

src/poetry/puzzle/provider.py

+6-102
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
from __future__ import annotations
22

3-
import functools
43
import logging
5-
import os
64
import re
7-
import tempfile
85
import time
9-
import urllib.parse
106

117
from collections import defaultdict
128
from contextlib import contextmanager
13-
from pathlib import Path
149
from typing import TYPE_CHECKING
1510
from typing import cast
1611

@@ -22,26 +17,24 @@
2217
from poetry.core.version.markers import EmptyMarker
2318
from poetry.core.version.markers import MarkerUnion
2419

25-
from poetry.inspection.info import PackageInfo
26-
from poetry.inspection.info import PackageInfoError
2720
from poetry.mixology.incompatibility import Incompatibility
2821
from poetry.mixology.incompatibility_cause import DependencyCause
2922
from poetry.mixology.incompatibility_cause import PythonCause
3023
from poetry.mixology.term import Term
3124
from poetry.packages import DependencyPackage
25+
from poetry.packages.direct_origin import DirectOrigin
3226
from poetry.packages.package_collection import PackageCollection
3327
from poetry.puzzle.exceptions import OverrideNeeded
3428
from poetry.repositories.exceptions import PackageNotFound
35-
from poetry.utils.helpers import download_file
3629
from poetry.utils.helpers import get_file_hash
37-
from poetry.vcs.git import Git
3830

3931

4032
if TYPE_CHECKING:
4133
from collections.abc import Callable
4234
from collections.abc import Collection
4335
from collections.abc import Iterable
4436
from collections.abc import Iterator
37+
from pathlib import Path
4538

4639
from cleo.io.io import IO
4740
from packaging.utils import NormalizedName
@@ -100,39 +93,6 @@ def _formatter_elapsed(self) -> str:
10093
return f"{elapsed:.1f}s"
10194

10295

103-
@functools.lru_cache(maxsize=None)
104-
def _get_package_from_git(
105-
url: str,
106-
branch: str | None = None,
107-
tag: str | None = None,
108-
rev: str | None = None,
109-
subdirectory: str | None = None,
110-
source_root: Path | None = None,
111-
) -> Package:
112-
source = Git.clone(
113-
url=url,
114-
source_root=source_root,
115-
branch=branch,
116-
tag=tag,
117-
revision=rev,
118-
clean=False,
119-
)
120-
revision = Git.get_revision(source)
121-
122-
path = Path(source.path)
123-
if subdirectory:
124-
path = path.joinpath(subdirectory)
125-
126-
package = Provider.get_package_from_directory(path)
127-
package._source_type = "git"
128-
package._source_url = url
129-
package._source_reference = rev or tag or branch or "HEAD"
130-
package._source_resolved_reference = revision
131-
package._source_subdirectory = subdirectory
132-
133-
return package
134-
135-
13696
class Provider:
13797
UNSAFE_PACKAGES: set[str] = set()
13898

@@ -351,7 +311,7 @@ def _search_for_vcs(self, dependency: VCSDependency) -> Package:
351311
Basically, we clone the repository in a temporary directory
352312
and get the information we need by checking out the specified reference.
353313
"""
354-
package = self.get_package_from_vcs(
314+
package = DirectOrigin.get_package_from_vcs(
355315
dependency.vcs,
356316
dependency.source,
357317
branch=dependency.branch,
@@ -368,31 +328,9 @@ def _search_for_vcs(self, dependency: VCSDependency) -> Package:
368328

369329
return package
370330

371-
@staticmethod
372-
def get_package_from_vcs(
373-
vcs: str,
374-
url: str,
375-
branch: str | None = None,
376-
tag: str | None = None,
377-
rev: str | None = None,
378-
subdirectory: str | None = None,
379-
source_root: Path | None = None,
380-
) -> Package:
381-
if vcs != "git":
382-
raise ValueError(f"Unsupported VCS dependency {vcs}")
383-
384-
return _get_package_from_git(
385-
url=url,
386-
branch=branch,
387-
tag=tag,
388-
rev=rev,
389-
subdirectory=subdirectory,
390-
source_root=source_root,
391-
)
392-
393331
def _search_for_file(self, dependency: FileDependency) -> Package:
394332
dependency.validate(raise_error=True)
395-
package = self.get_package_from_file(dependency.full_path)
333+
package = DirectOrigin.get_package_from_file(dependency.full_path)
396334

397335
self.validate_package_for_dependency(dependency=dependency, package=package)
398336

@@ -408,22 +346,9 @@ def _search_for_file(self, dependency: FileDependency) -> Package:
408346

409347
return package
410348

411-
@classmethod
412-
def get_package_from_file(cls, file_path: Path) -> Package:
413-
try:
414-
package = PackageInfo.from_path(path=file_path).to_package(
415-
root_dir=file_path
416-
)
417-
except PackageInfoError:
418-
raise RuntimeError(
419-
f"Unable to determine package info from path: {file_path}"
420-
)
421-
422-
return package
423-
424349
def _search_for_directory(self, dependency: DirectoryDependency) -> Package:
425350
dependency.validate(raise_error=True)
426-
package = self.get_package_from_directory(dependency.full_path)
351+
package = DirectOrigin.get_package_from_directory(dependency.full_path)
427352

428353
self.validate_package_for_dependency(dependency=dependency, package=package)
429354

@@ -434,12 +359,8 @@ def _search_for_directory(self, dependency: DirectoryDependency) -> Package:
434359

435360
return package
436361

437-
@classmethod
438-
def get_package_from_directory(cls, directory: Path) -> Package:
439-
return PackageInfo.from_directory(path=directory).to_package(root_dir=directory)
440-
441362
def _search_for_url(self, dependency: URLDependency) -> Package:
442-
package = self.get_package_from_url(dependency.url)
363+
package = DirectOrigin.get_package_from_url(dependency.url)
443364

444365
self.validate_package_for_dependency(dependency=dependency, package=package)
445366

@@ -453,23 +374,6 @@ def _search_for_url(self, dependency: URLDependency) -> Package:
453374

454375
return package
455376

456-
@classmethod
457-
def get_package_from_url(cls, url: str) -> Package:
458-
file_name = os.path.basename(urllib.parse.urlparse(url).path)
459-
with tempfile.TemporaryDirectory() as temp_dir:
460-
dest = Path(temp_dir) / file_name
461-
download_file(url, dest)
462-
package = cls.get_package_from_file(dest)
463-
464-
package.files = [
465-
{"file": file_name, "hash": "sha256:" + get_file_hash(dest)}
466-
]
467-
468-
package._source_type = "url"
469-
package._source_url = url
470-
471-
return package
472-
473377
def _get_dependencies_with_overrides(
474378
self, dependencies: list[Dependency], package: DependencyPackage
475379
) -> list[Dependency]:

src/poetry/utils/dependency_specification.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from poetry.core.packages.dependency import Dependency
1717
from tomlkit.items import InlineTable
1818

19-
from poetry.puzzle.provider import Provider
19+
from poetry.packages.direct_origin import DirectOrigin
2020

2121

2222
if TYPE_CHECKING:
@@ -120,7 +120,7 @@ def _parse_git_url(self, requirement: str) -> DependencySpec | None:
120120
pair["subdirectory"] = parsed.subdirectory
121121

122122
source_root = self._env.path.joinpath("src") if self._env else None
123-
package = Provider.get_package_from_vcs(
123+
package = DirectOrigin.get_package_from_vcs(
124124
"git",
125125
url=url.url,
126126
rev=pair.get("rev"),
@@ -139,7 +139,7 @@ def _parse_url(self, requirement: str) -> DependencySpec | None:
139139
return self._parse_git_url(requirement)
140140

141141
if url_parsed.scheme in ["http", "https"]:
142-
package = Provider.get_package_from_url(requirement)
142+
package = DirectOrigin.get_package_from_url(requirement)
143143
assert package.source_url is not None
144144
return {"name": package.name, "url": package.source_url}
145145

@@ -158,9 +158,9 @@ def _parse_path(self, requirement: str) -> DependencySpec | None:
158158
path = self._cwd.joinpath(requirement)
159159

160160
if path.is_file():
161-
package = Provider.get_package_from_file(path.resolve())
161+
package = DirectOrigin.get_package_from_file(path.resolve())
162162
else:
163-
package = Provider.get_package_from_directory(path.resolve())
163+
package = DirectOrigin.get_package_from_directory(path.resolve())
164164

165165
return {
166166
"name": package.name,

tests/conftest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ def mock_user_config_dir(mocker: MockerFixture, config_dir: Path) -> None:
239239
def download_mock(mocker: MockerFixture) -> None:
240240
# Patch download to not download anything but to just copy from fixtures
241241
mocker.patch("poetry.utils.helpers.download_file", new=mock_download)
242-
mocker.patch("poetry.puzzle.provider.download_file", new=mock_download)
242+
mocker.patch("poetry.packages.direct_origin.download_file", new=mock_download)
243243
mocker.patch("poetry.repositories.http_repository.download_file", new=mock_download)
244244

245245

0 commit comments

Comments
 (0)