Repository URL to install this package:
|
Version:
41.0.1 ▾
|
import mock
import os
import re
from distutils import log
from distutils.errors import DistutilsError
import pytest
from setuptools.command.upload import upload
from setuptools.dist import Distribution
from setuptools.extern import six
def _parse_upload_body(body):
boundary = u'\r\n----------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
entries = []
name_re = re.compile(u'^Content-Disposition: form-data; name="([^\"]+)"')
for entry in body.split(boundary):
pair = entry.split(u'\r\n\r\n')
if not len(pair) == 2:
continue
key, value = map(six.text_type.strip, pair)
m = name_re.match(key)
if m is not None:
key = m.group(1)
entries.append((key, value))
return entries
@pytest.fixture
def patched_upload(tmpdir):
class Fix:
def __init__(self, cmd, urlopen):
self.cmd = cmd
self.urlopen = urlopen
def __iter__(self):
return iter((self.cmd, self.urlopen))
def get_uploaded_metadata(self):
request = self.urlopen.call_args_list[0][0][0]
body = request.data.decode('utf-8')
entries = dict(_parse_upload_body(body))
return entries
class ResponseMock(mock.Mock):
def getheader(self, name, default=None):
"""Mocked getheader method for response object"""
return {
'content-type': 'text/plain; charset=utf-8',
}.get(name.lower(), default)
with mock.patch('setuptools.command.upload.urlopen') as urlopen:
urlopen.return_value = ResponseMock()
urlopen.return_value.getcode.return_value = 200
urlopen.return_value.read.return_value = b''
content = os.path.join(str(tmpdir), "content_data")
with open(content, 'w') as f:
f.write("Some content")
dist = Distribution()
dist.dist_files = [('sdist', '3.7.0', content)]
cmd = upload(dist)
cmd.announce = mock.Mock()
cmd.username = 'user'
cmd.password = 'hunter2'
yield Fix(cmd, urlopen)
class TestUploadTest:
def test_upload_metadata(self, patched_upload):
cmd, patch = patched_upload
# Set the metadata version to 2.1
cmd.distribution.metadata.metadata_version = '2.1'
# Run the command
cmd.ensure_finalized()
cmd.run()
# Make sure we did the upload
patch.assert_called_once()
# Make sure the metadata version is correct in the headers
entries = patched_upload.get_uploaded_metadata()
assert entries['metadata_version'] == '2.1'
def test_warns_deprecation(self):
dist = Distribution()
dist.dist_files = [(mock.Mock(), mock.Mock(), mock.Mock())]
cmd = upload(dist)
cmd.upload_file = mock.Mock()
cmd.announce = mock.Mock()
cmd.run()
cmd.announce.assert_called_once_with(
"WARNING: Uploading via this command is deprecated, use twine to "
"upload instead (https://pypi.org/p/twine/)",
log.WARN
)
def test_warns_deprecation_when_raising(self):
dist = Distribution()
dist.dist_files = [(mock.Mock(), mock.Mock(), mock.Mock())]
cmd = upload(dist)
cmd.upload_file = mock.Mock()
cmd.upload_file.side_effect = Exception
cmd.announce = mock.Mock()
with pytest.raises(Exception):
cmd.run()
cmd.announce.assert_called_once_with(
"WARNING: Uploading via this command is deprecated, use twine to "
"upload instead (https://pypi.org/p/twine/)",
log.WARN
)
@pytest.mark.parametrize('url', [
'https://example.com/a;parameter', # Has parameters
'https://example.com/a?query', # Has query
'https://example.com/a#fragment', # Has fragment
'ftp://example.com', # Invalid scheme
])
def test_upload_file_invalid_url(self, url, patched_upload):
patched_upload.urlopen.side_effect = Exception("Should not be reached")
cmd = patched_upload.cmd
cmd.repository = url
cmd.ensure_finalized()
with pytest.raises(AssertionError):
cmd.run()
def test_upload_file_http_error(self, patched_upload):
patched_upload.urlopen.side_effect = six.moves.urllib.error.HTTPError(
'https://example.com',
404,
'File not found',
None,
None
)
cmd = patched_upload.cmd
cmd.ensure_finalized()
with pytest.raises(DistutilsError):
cmd.run()
cmd.announce.assert_any_call(
'Upload failed (404): File not found',
log.ERROR)
def test_upload_file_os_error(self, patched_upload):
patched_upload.urlopen.side_effect = OSError("Invalid")
cmd = patched_upload.cmd
cmd.ensure_finalized()
with pytest.raises(OSError):
cmd.run()
cmd.announce.assert_any_call('Invalid', log.ERROR)
@mock.patch('setuptools.command.upload.spawn')
def test_upload_file_gpg(self, spawn, patched_upload):
cmd, urlopen = patched_upload
cmd.sign = True
cmd.identity = "Alice"
cmd.dry_run = True
content_fname = cmd.distribution.dist_files[0][2]
signed_file = content_fname + '.asc'
with open(signed_file, 'wb') as f:
f.write("signed-data".encode('utf-8'))
cmd.ensure_finalized()
cmd.run()
# Make sure that GPG was called
spawn.assert_called_once_with([
"gpg", "--detach-sign", "--local-user", "Alice", "-a",
content_fname
], dry_run=True)
# Read the 'signed' data that was transmitted
entries = patched_upload.get_uploaded_metadata()
assert entries['gpg_signature'] == 'signed-data'
def test_show_response_no_error(self, patched_upload):
# This test is just that show_response doesn't throw an error
# It is not really important what the printed response looks like
# in a deprecated command, but we don't want to introduce new
# errors when importing this function from distutils
patched_upload.cmd.show_response = True
patched_upload.cmd.ensure_finalized()
patched_upload.cmd.run()