Skip to content

Commit

Permalink
Merge pull request #365 from pypa/settings-object
Browse files Browse the repository at this point in the history
Add a Settings object to advance Twine having a Real API
  • Loading branch information
sigmavirus24 committed May 17, 2018
2 parents 2ab1a60 + b341906 commit f2695b0
Show file tree
Hide file tree
Showing 8 changed files with 467 additions and 261 deletions.
57 changes: 57 additions & 0 deletions tests/test_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Tests for the Settings class and module."""
# Copyright 2018 Ian Stapleton Cordasco
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import unicode_literals
import os.path
import textwrap

from twine import exceptions
from twine import settings

import pytest


def test_settings_takes_no_positional_arguments():
"""Verify that the Settings initialization is kw-only."""
with pytest.raises(TypeError):
settings.Settings('a', 'b', 'c')


def test_settings_transforms_config(tmpdir):
"""Verify that the settings object transforms the passed in options."""
pypirc = os.path.join(str(tmpdir), ".pypirc")

with open(pypirc, "w") as fp:
fp.write(textwrap.dedent("""
[pypi]
repository: https://upload.pypi.org/legacy/
username:username
password:password
"""))
s = settings.Settings(config_file=pypirc)
assert (s.repository_config['repository'] ==
'https://upload.pypi.org/legacy/')
assert s.sign is False
assert s.sign_with == 'gpg'
assert s.identity is None
assert s.username == 'username'
assert s.password == 'password'
assert s.cacert is None
assert s.client_cert is None


def test_identity_requires_sign():
"""Verify that if a user passes identity, we require sign=True."""
with pytest.raises(exceptions.InvalidSigningConfiguration):
settings.Settings(sign=False, identity='fakeid')
42 changes: 19 additions & 23 deletions tests/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import pytest

from twine.commands import upload
from twine import package, cli, exceptions
from twine import package, cli, exceptions, settings
import twine

import helpers
Expand Down Expand Up @@ -69,7 +69,6 @@ def test_find_dists_handles_real_files():

def test_get_config_old_format(tmpdir):
pypirc = os.path.join(str(tmpdir), ".pypirc")
dists = ["tests/fixtures/twine-1.5.0-py2.py3-none-any.whl"]

with open(pypirc, "w") as fp:
fp.write(textwrap.dedent("""
Expand All @@ -79,12 +78,12 @@ def test_get_config_old_format(tmpdir):
"""))

try:
upload.upload(dists=dists, repository="pypi", sign=None, identity=None,
username=None, password=None, comment=None,
cert=None, client_cert=None,
sign_with=None, config_file=pypirc, skip_existing=False,
repository_url=None, verbose=None,
)
settings.Settings(
repository="pypi", sign=None, identity=None, username=None,
password=None, comment=None, cert=None, client_cert=None,
sign_with=None, config_file=pypirc, skip_existing=False,
repository_url=None, verbose=None,
)
except KeyError as err:
assert err.args[0] == (
"Missing 'pypi' section from the configuration file\n"
Expand All @@ -108,12 +107,14 @@ def test_deprecated_repo(tmpdir):
password:bar
"""))

upload.upload(dists=dists, repository="pypi", sign=None, identity=None,
username=None, password=None, comment=None,
cert=None, client_cert=None,
sign_with=None, config_file=pypirc, skip_existing=False,
repository_url=None, verbose=None,
)
upload_settings = settings.Settings(
repository="pypi", sign=None, identity=None, username=None,
password=None, comment=None, cert=None, client_cert=None,
sign_with=None, config_file=pypirc, skip_existing=False,
repository_url=None, verbose=None,
)

upload.upload(upload_settings, dists)

assert err.args[0] == (
"You're trying to upload to the legacy PyPI site "
Expand Down Expand Up @@ -178,12 +179,7 @@ def none_upload(*args, **kwargs):
"TWINE_CERT": "/foo/bar.crt"}
with helpers.set_env(**testenv):
cli.dispatch(["upload", "path/to/file"])
cli.dispatch(["upload", "path/to/file"])
result_kwargs = replaced_upload.calls[0].kwargs
assert "pypipassword" == result_kwargs["password"]
assert "pypiuser" == result_kwargs["username"]
assert "/foo/bar.crt" == result_kwargs["cert"]
result_kwargs = replaced_upload.calls[1].kwargs
assert None is result_kwargs["password"]
assert None is result_kwargs["username"]
assert None is result_kwargs["cert"]
upload_settings = replaced_upload.calls[0].args[0]
assert "pypipassword" == upload_settings.password
assert "pypiuser" == upload_settings.username
assert "/foo/bar.crt" == upload_settings.cacert
24 changes: 24 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,27 @@ def test_get_password_runtime_error_suppressed(
assert len(recwarn) == 1
warning = recwarn.pop(UserWarning)
assert 'fail!' in str(warning)


def test_no_positional_on_method():
class T(object):
@utils.no_positional(allow_self=True)
def __init__(self, foo=False):
self.foo = foo

with pytest.raises(TypeError):
T(1)

t = T(foo=True)
assert t.foo


def test_no_positional_on_function():
@utils.no_positional()
def t(foo=False):
return foo

with pytest.raises(TypeError):
t(1)

assert t(foo=True)
101 changes: 12 additions & 89 deletions twine/commands/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,122 +18,45 @@

from twine import exceptions as exc
from twine.package import PackageFile
from twine.repository import Repository
from twine import utils
from twine import settings


def register(package, repository, username, password, comment, config_file,
cert, client_cert, repository_url):
config = utils.get_repository_from_config(
config_file,
repository,
repository_url,
)
config["repository"] = utils.normalize_repository_url(
config["repository"]
)

print("Registering package to {0}".format(config["repository"]))
def register(register_settings, package):
repository_url = register_settings.repository_config['repository']

username = utils.get_username(username, config)
password = utils.get_password(
config["repository"], username, password, config,
)
ca_cert = utils.get_cacert(cert, config)
client_cert = utils.get_clientcert(client_cert, config)

repository = Repository(config["repository"], username, password)
repository.set_certificate_authority(ca_cert)
repository.set_client_certificate(client_cert)
print("Registering package to {0}".format(repository_url))
repository = register_settings.create_repository()

if not os.path.exists(package):
raise exc.PackageNotFound(
'"{0}" does not exist on the file system.'.format(package)
)

resp = repository.register(PackageFile.from_filename(package, comment))
resp = repository.register(
PackageFile.from_filename(package, register_settings.comment)
)
repository.close()

if resp.is_redirect:
raise exc.RedirectDetected(
('"{0}" attempted to redirect to "{1}" during registration.'
' Aborting...').format(config["repository"],
' Aborting...').format(repository_url,
resp.headers["location"]))

resp.raise_for_status()


def main(args):
parser = argparse.ArgumentParser(prog="twine register")
parser.add_argument(
"-r", "--repository",
action=utils.EnvironmentDefault,
env="TWINE_REPOSITORY",
default=None,
help="The repository (package index) to register the package to. "
"Should be a section in the config file. (Can also be set "
"via %(env)s environment variable.) "
"Initial package registration no longer necessary on pypi.org: "
"https://packaging.python.org/guides/migrating-to-pypi-org/",
)
parser.add_argument(
"--repository-url",
action=utils.EnvironmentDefault,
env="TWINE_REPOSITORY_URL",
default=None,
required=False,
help="The repository (package index) URL to register the package to. "
"This overrides --repository. "
"(Can also be set via %(env)s environment variable.)"
)
parser.add_argument(
"-u", "--username",
action=utils.EnvironmentDefault,
env="TWINE_USERNAME",
required=False, help="The username to authenticate to the repository "
"(package index) as. (Can also be set via "
"%(env)s environment variable.)",
)
parser.add_argument(
"-p", "--password",
action=utils.EnvironmentDefault,
env="TWINE_PASSWORD",
required=False, help="The password to authenticate to the repository "
"(package index) with. (Can also be set via "
"%(env)s environment variable.)",
)
parser.add_argument(
"-c", "--comment",
help="The comment to include with the distribution file.",
)
parser.add_argument(
"--config-file",
default="~/.pypirc",
help="The .pypirc config file to use.",
)
parser.add_argument(
"--cert",
action=utils.EnvironmentDefault,
env="TWINE_CERT",
default=None,
required=False,
metavar="path",
help="Path to alternate CA bundle (can also be set via %(env)s "
"environment variable).",
)
parser.add_argument(
"--client-cert",
metavar="path",
help="Path to SSL client certificate, a single file containing the "
"private key and the certificate in PEM format.",
)
settings.Settings.register_argparse_arguments(parser)
parser.add_argument(
"package",
metavar="package",
help="File from which we read the package metadata.",
)

args = parser.parse_args(args)
register_settings = settings.Settings.from_argparse(args)

# Call the register function with the args from the command line
register(**vars(args))
register(register_settings, args.package)

0 comments on commit f2695b0

Please sign in to comment.