Commit 4295c3e0 authored by Stefano Rivera's avatar Stefano Rivera

Update upstream source from tag 'upstream/1.12.1'

Update to upstream version '1.12.1'
with Debian dir 268d324cecb64180e6476bc1b26948cac2d9a2b0
parents dadcd554 d2869253
[run]
branch = True
[report]
# Regexes for lines to exclude from consideration
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover
# Don't complain if non-runnable code isn't run
if __name__ == .__main__.:
# Paths to omit from consideration
omit =
# __main__.py exists only as a very basic wrapper around warehouse.cli
# and exists only to provide setuptools and python -m a place to point
# at.
*/twine/__main__.py
......@@ -18,3 +18,8 @@ Andrew Watts <andrewwatts@gmail.com>
Anna Martelli Ravenscroft <annaraven@gmail.com>
Sumana Harihareswara <sh@changeset.nyc>
Dustin Ingram <di@di.codes> (https://di.codes)
Jesse Jarzynka <jesse@jessejoe.com> (http://jessejoe.com)
László Kiss Kollár <kiss.kollar.laszlo@gmail.com>
Frances Hocutt <frances.hocutt@gmail.com>
Tathagata Dasgupta <tathagatadg@gmail.com>
Wasim Thabraze <wasim@thabraze.me>
\ No newline at end of file
include LICENSE
include README.rst
include AUTHORS
include .coveragerc
recursive-include tests *.py
recursive-include docs *.bat
recursive-include docs *.empty
recursive-include docs *.py
recursive-include docs *.rst
recursive-include docs Makefile
recursive-include tests *.py *.whl deprecated-pypirc
recursive-include docs *.bat *.empty *.py *.rst Makefile *.txt
prune docs/_build
prune *.yml
Metadata-Version: 2.1
Name: twine
Version: 1.11.0
Version: 1.12.1
Summary: Collection of utilities for publishing packages on PyPI
Home-page: https://twine.readthedocs.io/
Author: Donald Stufft and individual contributors
Author-email: donald@stufft.io
License: Apache License, Version 2.0
Project-URL: Twine source, https://github.com/pypa/twine/
Project-URL: Packaging tutorial, https://packaging.python.org/tutorials/distributing-packages/
Project-URL: Twine documentation, https://twine.readthedocs.io/en/latest/
Project-URL: Twine source, https://github.com/pypa/twine/
Description: twine
=====
.. rtd-inclusion-marker-do-not-remove
Twine is `a utility`_ for `publishing`_ packages on `PyPI`_.
Twine is `a utility`_ for `publishing`_ Python packages on `PyPI`_.
Currently it only supports registering `projects`_ and uploading `distributions`_.
It provides build system independent uploads of source and binary
`distribution artifacts <distributions>`_ for both new and existing
`projects`_.
Why Should I Use This?
......@@ -26,17 +28,16 @@ Description: twine
security and testability.
The biggest reason to use ``twine`` is that it securely authenticates
you to `PyPI`_ over HTTPS using a verified connection, while ``python
setup.py upload`` `only recently stopped using HTTP
<https://bugs.python.org/issue12226>`_ in Python 2.7.9+ and Python
3.2+. This means anytime you use ``python setup.py upload`` with an
older Python version, you expose your username and password to being
easily sniffed. Twine uses only verified TLS to upload to PyPI,
protecting your credentials from theft.
you to `PyPI`_ over HTTPS using a verified connection regardless of
the underlying Python version, while whether or not
``python setup.py upload`` will work correctly and securely depends
on your build system, your Python version and the underlying operating
system.
Secondly, it allows you to precreate your distribution files.
``python setup.py upload`` only allows you to upload something that you've
created in the same command invocation. This means that you cannot test the
``python setup.py upload`` only allows you to upload something that you're
building with ``distutils`` or ``setuptools``, and created in the same
command invocation. This means that you cannot test the
exact file you're going to upload to PyPI to ensure that it works before
uploading it.
......@@ -144,10 +145,24 @@ Description: twine
.. _`Using Keyring on headless systems`:
https://keyring.readthedocs.io/en/latest/#using-keyring-on-headless-linux-systems
Disabling Keyring
^^^^^^^^^^^^^^^^^
In some cases, the presence of keyring may be problemmatic. To disable
keyring and defer to a prompt for passwords, uninstall ``keyring``
or if that's not an option, you can also configure keyring to be disabled.
See `twine 338 <https://github.com/pypa/twine/issues/338>`_ for a
discussion on ways to do that.
Options
-------
``twine upload``
^^^^^^^^^^^^^^^^
Uploads one or more distributions to a repository.
.. code-block:: console
$ twine upload -h
......@@ -201,16 +216,29 @@ Description: twine
containing the private key and the certificate in PEM
format.
Twine also includes a ``register`` command.
``twine check``
^^^^^^^^^^^^^^^
Checks whether your distributions long description will render correctly on PyPI.
.. code-block:: console
$ twine check -h
usage: twine check [-h] dist [dist ...]
positional arguments:
dist The distribution files to check, usually dist/*
optional arguments:
-h, --help show this help message and exit
``twine register``
^^^^^^^^^^^^^^^^^^
.. WARNING::
``register`` is `no longer necessary if you are
uploading to pypi.org
<https://packaging.python.org/guides/migrating-to-pypi-org/#registering-package-names-metadata>`_. As
such, it is `no longer supported
<https://github.com/pypa/warehouse/issues/1627>`_ in `Warehouse`_
(the new PyPI software running on pypi.org). However, you may need
this if you are using a different package index.
**WARNING**: The ``register`` command is `no longer necessary if you are uploading to
pypi.org`_. As such, it is `no longer supported`_ in `Warehouse`_ (the new
PyPI software running on pypi.org). However, you may need this if you are using
a different package index.
For completeness, its usage:
......@@ -310,6 +338,8 @@ Description: twine
.. _`PyPA Code of Conduct`: https://www.pypa.io/en/latest/code-of-conduct/
.. _`Warehouse`: https://github.com/pypa/warehouse
.. _`wheels`: https://packaging.python.org/glossary/#term-wheel
.. _`no longer necessary if you are uploading to pypi.org`: https://packaging.python.org/guides/migrating-to-pypi-org/#registering-package-names-metadata
.. _`no longer supported`: https://github.com/pypa/warehouse/issues/1627
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
......@@ -324,7 +354,6 @@ Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
......
......@@ -3,9 +3,11 @@ twine
.. rtd-inclusion-marker-do-not-remove
Twine is `a utility`_ for `publishing`_ packages on `PyPI`_.
Twine is `a utility`_ for `publishing`_ Python packages on `PyPI`_.
Currently it only supports registering `projects`_ and uploading `distributions`_.
It provides build system independent uploads of source and binary
`distribution artifacts <distributions>`_ for both new and existing
`projects`_.
Why Should I Use This?
......@@ -15,17 +17,16 @@ The goal of ``twine`` is to improve PyPI interaction by improving
security and testability.
The biggest reason to use ``twine`` is that it securely authenticates
you to `PyPI`_ over HTTPS using a verified connection, while ``python
setup.py upload`` `only recently stopped using HTTP
<https://bugs.python.org/issue12226>`_ in Python 2.7.9+ and Python
3.2+. This means anytime you use ``python setup.py upload`` with an
older Python version, you expose your username and password to being
easily sniffed. Twine uses only verified TLS to upload to PyPI,
protecting your credentials from theft.
you to `PyPI`_ over HTTPS using a verified connection regardless of
the underlying Python version, while whether or not
``python setup.py upload`` will work correctly and securely depends
on your build system, your Python version and the underlying operating
system.
Secondly, it allows you to precreate your distribution files.
``python setup.py upload`` only allows you to upload something that you've
created in the same command invocation. This means that you cannot test the
``python setup.py upload`` only allows you to upload something that you're
building with ``distutils`` or ``setuptools``, and created in the same
command invocation. This means that you cannot test the
exact file you're going to upload to PyPI to ensure that it works before
uploading it.
......@@ -133,10 +134,24 @@ The next time you run ``twine`` it will prompt you for a username and will grab
.. _`Using Keyring on headless systems`:
https://keyring.readthedocs.io/en/latest/#using-keyring-on-headless-linux-systems
Disabling Keyring
^^^^^^^^^^^^^^^^^
In some cases, the presence of keyring may be problemmatic. To disable
keyring and defer to a prompt for passwords, uninstall ``keyring``
or if that's not an option, you can also configure keyring to be disabled.
See `twine 338 <https://github.com/pypa/twine/issues/338>`_ for a
discussion on ways to do that.
Options
-------
``twine upload``
^^^^^^^^^^^^^^^^
Uploads one or more distributions to a repository.
.. code-block:: console
$ twine upload -h
......@@ -190,16 +205,29 @@ Options
containing the private key and the certificate in PEM
format.
Twine also includes a ``register`` command.
``twine check``
^^^^^^^^^^^^^^^
Checks whether your distributions long description will render correctly on PyPI.
.. code-block:: console
$ twine check -h
usage: twine check [-h] dist [dist ...]
positional arguments:
dist The distribution files to check, usually dist/*
optional arguments:
-h, --help show this help message and exit
``twine register``
^^^^^^^^^^^^^^^^^^
.. WARNING::
``register`` is `no longer necessary if you are
uploading to pypi.org
<https://packaging.python.org/guides/migrating-to-pypi-org/#registering-package-names-metadata>`_. As
such, it is `no longer supported
<https://github.com/pypa/warehouse/issues/1627>`_ in `Warehouse`_
(the new PyPI software running on pypi.org). However, you may need
this if you are using a different package index.
**WARNING**: The ``register`` command is `no longer necessary if you are uploading to
pypi.org`_. As such, it is `no longer supported`_ in `Warehouse`_ (the new
PyPI software running on pypi.org). However, you may need this if you are using
a different package index.
For completeness, its usage:
......@@ -299,3 +327,5 @@ trackers, chat rooms, and mailing lists is expected to follow the
.. _`PyPA Code of Conduct`: https://www.pypa.io/en/latest/code-of-conduct/
.. _`Warehouse`: https://github.com/pypa/warehouse
.. _`wheels`: https://packaging.python.org/glossary/#term-wheel
.. _`no longer necessary if you are uploading to pypi.org`: https://packaging.python.org/guides/migrating-to-pypi-org/#registering-package-names-metadata
.. _`no longer supported`: https://github.com/pypa/warehouse/issues/1627
......@@ -4,6 +4,13 @@
Changelog
=========
* :release:`1.12.1 <2018-09-24>`
* :bug:`404` Fix regression with upload exit code
* :release:`1.12.0 <2018-09-24>`
* :feature:`395 major` Add ``twine check`` command to check long description
* :feature:`392 major` Drop support for Python 3.3
* :feature:`363` Empower ``--skip-existing`` for Artifactory repositories
* :bug:`367` Avoid MD5 when Python is compiled in FIPS mode
* :release:`1.11.0 <2018-03-19>`
* :bug:`269 major` Avoid uploading to PyPI when given alternate
repository URL, and require ``http://`` or ``https://`` in
......
......@@ -73,7 +73,7 @@ Either use ``tox`` to build against all supported Python versions (if
you have them installed) or use ``tox -e py{version}`` to test against
a specific version, e.g., ``tox -e py27`` or ``tox -e py34``.
Also, always run ``tox -e pep8`` before submitting a pull request.
Also, always run ``tox -e lint`` before submitting a pull request.
Submitting changes
^^^^^^^^^^^^^^^^^^
......@@ -157,7 +157,7 @@ A checklist for creating, testing, and distributing a new version.
#. Run Twine tests:
#. ``tox -e py{27,34,35,36,py}``
#. ``tox -e pep8`` for the linter
#. ``tox -e lint`` for the linter
#. ``tox -e docs`` (this checks the Sphinx docs and uses
``readme_renderer`` to check that the ``long_description`` and other
metadata will render fine on the PyPI description)
......
doc8>=0.8.0
readme-renderer>=17.4
releases>=1.4.0
Sphinx>=1.7.0
sphinx_rtd_theme>=0.2.4
tox>=2.9.1
twine>=1.10.0
[wheel]
[bdist_wheel]
universal = 1
[check-manifest]
ignore =
.travis.yml
tox.ini
.github
.github/*
[metadata]
license_file = LICENSE
requires-dist =
tqdm >= 4.14
requests >= 2.5.0, != 2.15, != 2.16
requests-toolbelt >= 0.8.0
pkginfo >= 1.4.2
setuptools >= 0.7.0
argparse; python_version == '2.6'
pyblake2; extra == 'with-blake2' and python_version < '3.6'
keyring; extra == 'keyring'
......
......@@ -18,20 +18,6 @@ import sys
import twine
install_requires = [
"tqdm >= 4.14",
"pkginfo >= 1.4.2",
"requests >= 2.5.0, != 2.15, != 2.16",
"requests-toolbelt >= 0.8.0",
"setuptools >= 0.7.0",
]
if sys.version_info[:2] < (2, 7):
install_requires += [
"argparse",
]
blake2_requires = []
if sys.version_info[:2] < (3, 6):
......@@ -70,7 +56,6 @@ setup(
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
......@@ -82,6 +67,7 @@ setup(
entry_points={
"twine.registered_commands": [
"check = twine.commands.check:main",
"upload = twine.commands.upload:main",
"register = twine.commands.register:main",
],
......@@ -90,7 +76,14 @@ setup(
],
},
install_requires=install_requires,
install_requires=[
"pkginfo >= 1.4.2",
"readme_renderer >= 21.0",
"requests >= 2.5.0, != 2.15, != 2.16",
"requests-toolbelt >= 0.8.0",
"setuptools >= 0.7.0",
"tqdm >= 4.14",
],
extras_require={
'with-blake2': blake2_requires,
'keyring': [
......
[server-login]
username:testusername
password:testpassword
[pypi]
foo:bar
# Copyright 2018 Dustin Ingram
#
# 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 pretend
from twine.commands import check
def test_warningstream_write_match():
stream = check._WarningStream()
stream.output = pretend.stub(write=pretend.call_recorder(lambda a: None))
stream.write("<string>:2: (WARNING/2) Title underline too short.")
assert stream.output.write.calls == [
pretend.call("line 2: Warning: Title underline too short.\n")
]
def test_warningstream_write_nomatch():
stream = check._WarningStream()
stream.output = pretend.stub(write=pretend.call_recorder(lambda a: None))
stream.write("this does not match")
assert stream.output.write.calls == [pretend.call("this does not match")]
def test_warningstream_str():
stream = check._WarningStream()
stream.output = pretend.stub(getvalue=lambda: "result")
assert str(stream) == "result"
def test_check_no_distributions(monkeypatch):
stream = check.StringIO()
monkeypatch.setattr(check, "_find_dists", lambda a: [])
assert not check.check("dist/*", output_stream=stream)
assert stream.getvalue() == ""
def test_check_passing_distribution(monkeypatch):
renderer = pretend.stub(
render=pretend.call_recorder(lambda *a, **kw: "valid")
)
package = pretend.stub(metadata_dictionary=lambda: {"description": "blah"})
output_stream = check.StringIO()
warning_stream = ""
monkeypatch.setattr(check, "_RENDERERS", {"": renderer})
monkeypatch.setattr(check, "_find_dists", lambda a: ["dist/dist.tar.gz"])
monkeypatch.setattr(
check,
"PackageFile",
pretend.stub(from_filename=lambda *a, **kw: package),
)
monkeypatch.setattr(check, "_WarningStream", lambda: warning_stream)
assert not check.check("dist/*", output_stream=output_stream)
assert (
output_stream.getvalue()
== "Checking distribution dist/dist.tar.gz: Passed\n"
)
assert renderer.render.calls == [
pretend.call("blah", stream=warning_stream)
]
def test_check_failing_distribution(monkeypatch):
renderer = pretend.stub(
render=pretend.call_recorder(lambda *a, **kw: None)
)
package = pretend.stub(metadata_dictionary=lambda: {"description": "blah"})
output_stream = check.StringIO()
warning_stream = "WARNING"
monkeypatch.setattr(check, "_RENDERERS", {"": renderer})
monkeypatch.setattr(check, "_find_dists", lambda a: ["dist/dist.tar.gz"])
monkeypatch.setattr(
check,
"PackageFile",
pretend.stub(from_filename=lambda *a, **kw: package),
)
monkeypatch.setattr(check, "_WarningStream", lambda: warning_stream)
assert check.check("dist/*", output_stream=output_stream)
assert output_stream.getvalue() == (
"Checking distribution dist/dist.tar.gz: Failed\n"
"The project's long_description has invalid markup which will not be "
"rendered on PyPI. The following syntax errors were detected:\n"
"WARNING"
)
assert renderer.render.calls == [
pretend.call("blah", stream=warning_stream)
]
def test_main(monkeypatch):
check_result = pretend.stub()
check_stub = pretend.call_recorder(lambda a: check_result)
monkeypatch.setattr(check, "check", check_stub)
assert check.main(["dist/*"]) == check_result
assert check_stub.calls == [pretend.call(["dist/*"])]
import os
import pytest
from twine.commands import _find_dists, _group_wheel_files_first
from twine import exceptions
def test_ensure_wheel_files_uploaded_first():
files = _group_wheel_files_first(
["twine/foo.py", "twine/first.whl", "twine/bar.py", "twine/second.whl"]
)
expected = [
"twine/first.whl",
"twine/second.whl",
"twine/foo.py",
"twine/bar.py",
]
assert expected == files
def test_ensure_if_no_wheel_files():
files = _group_wheel_files_first(["twine/foo.py", "twine/bar.py"])
expected = ["twine/foo.py", "twine/bar.py"]
assert expected == files
def test_find_dists_expands_globs():
files = sorted(_find_dists(["twine/__*.py"]))
expected = [
os.path.join("twine", "__init__.py"),
os.path.join("twine", "__main__.py"),
]
assert expected == files
def test_find_dists_errors_on_invalid_globs():
with pytest.raises(exceptions.InvalidDistribution):
_find_dists(["twine/*.rb"])
def test_find_dists_handles_real_files():
expected = [
"twine/__init__.py",
"twine/__main__.py",
"twine/cli.py",
"twine/utils.py",
"twine/wheel.py",
]
files = _find_dists(expected)
assert expected == files
......@@ -11,11 +11,14 @@
# limitations under the License.
from twine import __main__ as dunder_main
from twine import exceptions
import pretend
def test_exception_handling(monkeypatch):
replaced_dispatch = pretend.raiser(KeyError('foo'))
replaced_dispatch = pretend.raiser(
exceptions.InvalidConfiguration('foo')
)
monkeypatch.setattr(dunder_main, 'dispatch', replaced_dispatch)
assert dunder_main.main() == 'KeyError: foo'
assert dunder_main.main() == 'InvalidConfiguration: foo'
......@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import unicode_literals
import platform
from twine import package
import pretend
......@@ -163,3 +164,47 @@ def test_metadata_dictionary(gpg_signature):
# GPG signature
assert result.get('gpg_signature') == gpg_signature
TWINE_1_5_0_WHEEL_HEXDIGEST = package.Hexdigest(
'1919f967e990bee7413e2a4bc35fd5d1',
'd86b0f33f0c7df49e888b11c43b417da5520cbdbce9f20618b1494b600061e67',
'b657a4148d05bd0098c1d6d8cc4e14e766dbe93c3a5ab6723b969da27a87bac0',
)
if platform.python_implementation().lower() == 'pypy':
# pyblake2 refuses to install on PyPy
TWINE_1_5_0_WHEEL_HEXDIGEST = TWINE_1_5_0_WHEEL_HEXDIGEST._replace(
blake2=None,
)
def test_hash_manager():
"""Verify our HashManager works."""
filename = 'tests/fixtures/twine-1.5.0-py2.py3-none-any.whl'
hasher = package.HashManager(filename)
hasher.hash()
assert hasher.hexdigest() == TWINE_1_5_0_WHEEL_HEXDIGEST
def test_fips_hash_manager(monkeypatch):
"""Verify the behaviour if hashlib is using FIPS mode."""
replaced_md5 = pretend.raiser(ValueError('fipsmode'))
monkeypatch.setattr(package.hashlib, 'md5', replaced_md5)
filename = 'tests/fixtures/twine-1.5.0-py2.py3-none-any.whl'
hasher = package.HashManager(filename)
hasher.hash()
hashes = TWINE_1_5_0_WHEEL_HEXDIGEST._replace(md5=None)
assert hasher.hexdigest() == hashes
def test_no_blake2_hash_manager(monkeypatch):
"""Verify the behaviour with missing blake2."""
monkeypatch.setattr(package, 'blake2b', None)
filename = 'tests/fixtures/twine-1.5.0-py2.py3-none-any.whl'
hasher = package.HashManager(filename)
hasher.hash()
hashes = TWINE_1_5_0_WHEEL_HEXDIGEST._replace(blake2=None)
assert hasher.hexdigest() == hashes
"""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')
......@@ -20,7 +20,7 @@ import pretend
import pytest
from twine.commands import upload
from twine import package, cli, exceptions
from twine import package, cli, exceptions, settings
import twine
import helpers
......@@ -28,48 +28,42 @@ import helpers
WHEEL_FIXTURE = 'tests/fixtures/twine-1.5.0-py2.py3-none-any.whl'
def test_ensure_wheel_files_uploaded_first():
files = upload.group_wheel_files_first(["twine/foo.py",
"twine/first.whl",
"twine/bar.py",
"twine/second.whl"])
expected = ["twine/first.whl",
"twine/second.whl",
"twine/foo.py",