Skip to content

Commit b1c2191

Browse files
Moved verbosity to the helper function, added unit tests, prints packages, size, and signatures (#652)
1 parent f922eeb commit b1c2191

File tree

4 files changed

+119
-12
lines changed

4 files changed

+119
-12
lines changed

tests/test_upload.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
import os
15+
1416
import pretend
1517
import pytest
1618
import requests
@@ -52,6 +54,50 @@ def upload_settings(make_settings, stub_repository):
5254
return upload_settings
5355

5456

57+
def test_make_package_pre_signed_dist(upload_settings, capsys):
58+
"""Create a PackageFile and print path, size, and user-provided signature."""
59+
filename = helpers.WHEEL_FIXTURE
60+
expected_size = "15.4 KB"
61+
signed_filename = helpers.WHEEL_FIXTURE + ".asc"
62+
signatures = {os.path.basename(signed_filename): signed_filename}
63+
64+
upload_settings.sign = True
65+
upload_settings.verbose = True
66+
67+
package = upload._make_package(filename, signatures, upload_settings)
68+
69+
assert package.filename == filename
70+
assert package.gpg_signature is not None
71+
72+
captured = capsys.readouterr()
73+
assert captured.out.count(f"{filename} ({expected_size})") == 1
74+
assert captured.out.count(f"Signed with {signed_filename}") == 1
75+
76+
77+
def test_make_package_unsigned_dist(upload_settings, monkeypatch, capsys):
78+
"""Create a PackageFile and print path, size, and Twine-generated signature."""
79+
filename = helpers.NEW_WHEEL_FIXTURE
80+
expected_size = "21.9 KB"
81+
signatures = {}
82+
83+
upload_settings.sign = True
84+
upload_settings.verbose = True
85+
86+
def stub_sign(package, *_):
87+
package.gpg_signature = (package.signed_basefilename, b"signature")
88+
89+
monkeypatch.setattr(package_file.PackageFile, "sign", stub_sign)
90+
91+
package = upload._make_package(filename, signatures, upload_settings)
92+
93+
assert package.filename == filename
94+
assert package.gpg_signature is not None
95+
96+
captured = capsys.readouterr()
97+
assert captured.out.count(f"{filename} ({expected_size})") == 1
98+
assert captured.out.count(f"Signed with {package.signed_filename}") == 1
99+
100+
55101
def test_successs_prints_release_urls(upload_settings, stub_repository, capsys):
56102
"""Print PyPI release URLS for each uploaded package."""
57103
stub_repository.release_urls = lambda packages: {RELEASE_URL, NEW_RELEASE_URL}
@@ -72,6 +118,26 @@ def test_successs_prints_release_urls(upload_settings, stub_repository, capsys):
72118
assert captured.out.count(NEW_RELEASE_URL) == 1
73119

74120

121+
def test_print_packages_if_verbose(upload_settings, capsys):
122+
"""Print the path and file size of each distribution attempting to be uploaded."""
123+
dists_to_upload = {
124+
helpers.WHEEL_FIXTURE: "15.4 KB",
125+
helpers.SDIST_FIXTURE: "20.8 KB",
126+
helpers.NEW_SDIST_FIXTURE: "26.1 KB",
127+
helpers.NEW_WHEEL_FIXTURE: "21.9 KB",
128+
}
129+
130+
upload_settings.verbose = True
131+
132+
result = upload.upload(upload_settings, dists_to_upload.keys())
133+
assert result is None
134+
135+
captured = capsys.readouterr()
136+
137+
for filename, size in dists_to_upload.items():
138+
assert captured.out.count(f"{filename} ({size})") == 1
139+
140+
75141
def test_success_with_pre_signed_distribution(upload_settings, stub_repository):
76142
"""Add GPG signature provided by user to uploaded package."""
77143
# Upload a pre-signed distribution

tests/test_utils.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,16 @@ def test_check_status_code_for_missing_status_code(capsys, repo_url):
294294

295295
captured = capsys.readouterr()
296296
assert captured.out == "NOTE: Try --verbose to see response content.\n"
297+
298+
299+
@pytest.mark.parametrize(
300+
("size_in_bytes, formatted_size"),
301+
[(3704, "3.6 KB"), (1153433, "1.1 MB"), (21412841, "20.4 MB")],
302+
)
303+
def test_get_file_size(size_in_bytes, formatted_size, monkeypatch):
304+
"""Get the size of file as a string with units."""
305+
monkeypatch.setattr(os.path, "getsize", lambda _: size_in_bytes)
306+
307+
file_size = utils.get_file_size(size_in_bytes)
308+
309+
assert file_size == formatted_size

twine/commands/upload.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414
import argparse
1515
import os.path
16+
from typing import Dict
1617
from typing import List
1718
from typing import cast
1819

@@ -50,24 +51,45 @@ def skip_upload(
5051
)
5152

5253

54+
def _make_package(
55+
filename: str, signatures: Dict[str, str], upload_settings: settings.Settings
56+
) -> package_file.PackageFile:
57+
"""Create and sign a package, based off of filename, signatures and settings."""
58+
package = package_file.PackageFile.from_filename(filename, upload_settings.comment)
59+
60+
signed_name = package.signed_basefilename
61+
if signed_name in signatures:
62+
package.add_gpg_signature(signatures[signed_name], signed_name)
63+
elif upload_settings.sign:
64+
package.sign(upload_settings.sign_with, upload_settings.identity)
65+
66+
if upload_settings.verbose:
67+
file_size = utils.get_file_size(package.filename)
68+
print(f" {package.filename} ({file_size})")
69+
if package.gpg_signature:
70+
print(f" Signed with {package.signed_filename}")
71+
72+
return package
73+
74+
5375
def upload(upload_settings: settings.Settings, dists: List[str]) -> None:
5476
dists = commands._find_dists(dists)
55-
5677
# Determine if the user has passed in pre-signed distributions
5778
signatures = {os.path.basename(d): d for d in dists if d.endswith(".asc")}
5879
uploads = [i for i in dists if not i.endswith(".asc")]
80+
5981
upload_settings.check_repository_url()
6082
repository_url = cast(str, upload_settings.repository_config["repository"])
61-
6283
print(f"Uploading distributions to {repository_url}")
6384

85+
packages_to_upload = [
86+
_make_package(filename, signatures, upload_settings) for filename in uploads
87+
]
88+
6489
repository = upload_settings.create_repository()
6590
uploaded_packages = []
6691

67-
for filename in uploads:
68-
package = package_file.PackageFile.from_filename(
69-
filename, upload_settings.comment
70-
)
92+
for package in packages_to_upload:
7193
skip_message = " Skipping {} because it appears to already exist".format(
7294
package.basefilename
7395
)
@@ -79,12 +101,6 @@ def upload(upload_settings: settings.Settings, dists: List[str]) -> None:
79101
print(skip_message)
80102
continue
81103

82-
signed_name = package.signed_basefilename
83-
if signed_name in signatures:
84-
package.add_gpg_signature(signatures[signed_name], signed_name)
85-
elif upload_settings.sign:
86-
package.sign(upload_settings.sign_with, upload_settings.identity)
87-
88104
resp = repository.upload(package)
89105

90106
# Bug 92. If we get a redirect we should abort because something seems

twine/utils.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,18 @@ def normalize_repository_url(url: str) -> str:
159159
return urlunparse(parsed)
160160

161161

162+
def get_file_size(filename: str) -> str:
163+
"""Return the size of a file in KB, or MB if >= 1024 KB."""
164+
file_size = os.path.getsize(filename) / 1024
165+
size_unit = "KB"
166+
167+
if file_size > 1024:
168+
file_size = file_size / 1024
169+
size_unit = "MB"
170+
171+
return f"{file_size:.1f} {size_unit}"
172+
173+
162174
def check_status_code(response: requests.Response, verbose: bool) -> None:
163175
"""Generate a helpful message based on the response from the repository.
164176

0 commit comments

Comments
 (0)