Skip to content

Commit d2e17a6

Browse files
authored
Merge branch 'main' into pre-commit-ci-update-config
2 parents 8d11478 + 2b0723c commit d2e17a6

File tree

19 files changed

+544
-123
lines changed

19 files changed

+544
-123
lines changed

docs/cli.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,9 +711,15 @@ poetry publish
711711
It can also build the package if you pass it the `--build` option.
712712

713713
{{% note %}}
714-
See [Publishable Repositories]({{< relref "repositories/#publishable-repositories" >}}) for more information on how to configure and use publishable repositories.
714+
See [Publishable Repositories]({{< relref "repositories/#publishable-repositories" >}}) for more information
715+
on how to configure and use publishable repositories.
715716
{{% /note %}}
716717

718+
{{% warning %}}
719+
Only artifacts of the latest version of your package in the dist directory will be uploaded.
720+
Older versions from previous builds as well as artifacts of other packages are ignored.
721+
{{% /warning %}}
722+
717723
#### Options
718724

719725
* `--repository (-r)`: The repository to register the package to (default: `pypi`).

poetry.lock

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

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ dependencies = [
88
"build (>=1.2.1,<2.0.0)",
99
"cachecontrol[filecache] (>=0.14.0,<0.15.0)",
1010
"cleo (>=2.1.0,<3.0.0)",
11-
"dulwich (>=0.24.0,<0.25.0)",
11+
"dulwich (>=0.25.0,<0.26.0)",
1212
"fastjsonschema (>=2.18.0,<3.0.0)",
1313
"installer (>=0.7.0,<0.8.0)",
1414
"keyring (>=25.1.0,<26.0.0)",

src/poetry/console/commands/publish.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ def handle(self) -> int:
8282

8383
self.call("build", args=f"--output {dist_dir}")
8484

85-
files = publisher.files
86-
if not files:
85+
publisher = Publisher(self.poetry, self.io, Path(dist_dir))
86+
87+
if not publisher.files:
8788
self.line_error(
8889
"<error>No files to publish. "
8990
"Run poetry build first or use the --build option.</error>"

src/poetry/publishing/publisher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def publish(
7979
repository_name = "PyPI"
8080
self._io.write_line(
8181
f"Publishing <c1>{self._package.pretty_name}</c1>"
82-
f" (<c2>{self._package.pretty_version}</c2>) to"
82+
f" (<c2>{self._uploader.version}</c2>) to"
8383
f" <info>{repository_name}</info>"
8484
)
8585

src/poetry/publishing/uploader.py

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
from __future__ import annotations
22

3+
import itertools
34
import tarfile
45
import zipfile
56

7+
from collections import defaultdict
8+
from functools import cached_property
69
from pathlib import Path
710
from typing import TYPE_CHECKING
811
from typing import Any
@@ -12,6 +15,7 @@
1215

1316
from packaging.metadata import RawMetadata
1417
from packaging.metadata import parse_email
18+
from poetry.core.constraints.version import Version
1519
from poetry.core.masonry.utils.helpers import distribution_name
1620
from requests_toolbelt import user_agent
1721
from requests_toolbelt.multipart import MultipartEncoder
@@ -36,7 +40,7 @@ class UploadError(Exception):
3640
class Uploader:
3741
def __init__(self, poetry: Poetry, io: IO, dist_dir: Path | None = None) -> None:
3842
self._poetry = poetry
39-
self._package = poetry.package
43+
self._dist_name = distribution_name(poetry.package.name)
4044
self._io = io
4145
self._dist_dir = dist_dir or self.default_dist_dir
4246
self._username: str | None = None
@@ -60,14 +64,39 @@ def dist_dir(self) -> Path:
6064

6165
@property
6266
def files(self) -> list[Path]:
63-
dist = self.dist_dir
64-
version = self._package.version.to_string()
65-
escaped_name = distribution_name(self._package.name)
67+
return self._files_and_version[0]
6668

67-
wheels = list(dist.glob(f"{escaped_name}-{version}-*.whl"))
68-
tars = list(dist.glob(f"{escaped_name}-{version}.tar.gz"))
69+
@property
70+
def version(self) -> str:
71+
return self._files_and_version[1]
6972

70-
return sorted(wheels + tars)
73+
@cached_property
74+
def _files_and_version(self) -> tuple[list[Path], str]:
75+
dist = self.dist_dir
76+
77+
wheels = dist.glob(f"{self._dist_name}-*-*.whl")
78+
tars = dist.glob(f"{self._dist_name}-*.tar.gz")
79+
artifacts_by_version = defaultdict(list)
80+
for artifact in itertools.chain(wheels, tars):
81+
version = (
82+
artifact.stem.removesuffix(".tar")
83+
.removeprefix(f"{self._dist_name}-")
84+
.split("-", maxsplit=1)[0]
85+
)
86+
artifacts_by_version[version].append(artifact)
87+
match len(artifacts_by_version):
88+
case 0:
89+
return [], ""
90+
case 1:
91+
latest_version = next(iter(artifacts_by_version))
92+
artifacts = artifacts_by_version[latest_version]
93+
case _:
94+
latest_version = max(
95+
artifacts_by_version, key=lambda v: Version.parse(v)
96+
)
97+
artifacts = artifacts_by_version[latest_version]
98+
99+
return sorted(artifacts, key=lambda a: (a.suffix == ".whl", a)), latest_version
71100

72101
def auth(self, username: str | None, password: str | None) -> None:
73102
self._username = username
@@ -258,14 +287,7 @@ def _register(self, session: requests.Session, url: str) -> requests.Response:
258287
"""
259288
Register a package to a repository.
260289
"""
261-
dist = self.dist_dir
262-
escaped_name = distribution_name(self._package.name)
263-
file = dist / f"{escaped_name}-{self._package.version.to_string()}.tar.gz"
264-
265-
if not file.exists():
266-
raise RuntimeError(f'"{file.name}" does not exist.')
267-
268-
data = self.post_data(file)
290+
data = self.post_data(self.files[0])
269291
data.update({":action": "submit", "protocol_version": "1"})
270292

271293
data_to_send = self._prepare_data(data)

src/poetry/puzzle/provider.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ def __init__(
151151
)
152152

153153
self.get_package_from_pool = functools.cache(self._pool.package)
154+
self._refreshed: set[tuple[str, Version, str | None]] = set()
154155

155156
@property
156157
def pool(self) -> RepositoryPool:
@@ -471,14 +472,34 @@ def complete_package(
471472
elif package.is_direct_origin():
472473
requires = package.requires
473474
else:
474-
dependency_package = DependencyPackage(
475-
dependency,
476-
self.get_package_from_pool(
475+
if (
476+
package.pretty_name,
477+
package.version,
478+
dependency.source_name,
479+
) in self._refreshed:
480+
# circumvent lru_cache to avoid unnecessary refresh
481+
pool_package = self.pool.package(
477482
package.pretty_name,
478483
package.version,
479484
repository_name=dependency.source_name,
480-
),
481-
)
485+
)
486+
else:
487+
pool_package = self.get_package_from_pool(
488+
package.pretty_name,
489+
package.version,
490+
repository_name=dependency.source_name,
491+
)
492+
if package.files and sorted(
493+
package.files, key=lambda f: f["file"]
494+
) != sorted(pool_package.files, key=lambda f: f["file"]):
495+
# This happens if additional artifacts are uploaded later. Either our own cache
496+
# is outdated or the lockfile has been created with an outdated cache.
497+
# Refresh to cover the first case. (It does not hurt much in the second case.)
498+
pool_package = self.pool.refresh(pool_package)
499+
self._refreshed.add(
500+
(package.pretty_name, package.version, dependency.source_name)
501+
)
502+
dependency_package = DependencyPackage(dependency, pool_package)
482503

483504
package = dependency_package.package
484505
dependency = dependency_package.dependency

src/poetry/repositories/cached_repository.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,6 @@ def package(self, name: str, version: Version) -> Package:
7070
return self.get_release_info(canonicalize_name(name), version).to_package(
7171
name=name
7272
)
73+
74+
def forget(self, name: str, version: Version) -> None:
75+
self._release_cache.forget(f"{canonicalize_name(name)}:{version}")

src/poetry/repositories/repository_pool.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from poetry.config.config import Config
1111
from poetry.repositories.abstract_repository import AbstractRepository
12+
from poetry.repositories.cached_repository import CachedRepository
1213
from poetry.repositories.exceptions import PackageNotFoundError
1314
from poetry.repositories.repository import Repository
1415
from poetry.utils.cache import ArtifactCache
@@ -181,3 +182,10 @@ def search(self, query: str | list[str]) -> list[Package]:
181182
for repo in self.repositories:
182183
results += repo.search(query)
183184
return results
185+
186+
def refresh(self, package: Package) -> Package:
187+
repository_name = package.source_reference or "PyPI"
188+
repo = self.repository(repository_name)
189+
if isinstance(repo, CachedRepository):
190+
repo.forget(package.name, package.version)
191+
return repo.package(package.name, package.version)

0 commit comments

Comments
 (0)