Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "check" command #395

Merged
merged 8 commits into from
Sep 16, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
install_requires = [
"tqdm >= 4.14",
"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",
Expand Down Expand Up @@ -81,6 +82,7 @@

entry_points={
"twine.registered_commands": [
"check = twine.commands.check:main",
"upload = twine.commands.upload:main",
"register = twine.commands.register:main",
],
Expand Down
119 changes: 119 additions & 0 deletions tests/test_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# 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/*"])]
50 changes: 50 additions & 0 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import os

import pytest

from twine.commands import _find_dists, _group_wheel_files_first


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(ValueError):
_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
39 changes: 0 additions & 39 deletions tests/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,45 +28,6 @@
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",
"twine/bar.py"]
assert expected == files


def test_ensure_if_no_wheel_files():
files = upload.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(upload.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(ValueError):
upload.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 = upload.find_dists(expected)
assert expected == files


def test_get_config_old_format(tmpdir):
pypirc = os.path.join(str(tmpdir), ".pypirc")

Expand Down
13 changes: 1 addition & 12 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@
import os.path
import textwrap

try:
import builtins
except ImportError:
import __builtin__ as builtins

import pytest

from twine import utils
Expand Down Expand Up @@ -239,13 +234,7 @@ def keyring_missing(monkeypatch):
"""
Simulate that 'import keyring' raises an ImportError
"""
real_import = builtins.__import__

def my_import(name, *args, **kwargs):
if name == 'keyring':
raise ImportError
return real_import(name, *args, **kwargs)
monkeypatch.setattr(builtins, '__import__', my_import)
monkeypatch.delitem(sys.modules, 'keyring', raising=False)


@pytest.fixture
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ deps =
pretend
pytest
py27,py34,py35: pyblake2
readme_renderer
commands =
coverage run --source twine -m pytest {posargs:tests}
coverage report -m
Expand Down
2 changes: 1 addition & 1 deletion twine/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ def dispatch(argv):

main = registered_commands[args.command].load()

main(args.args)
return main(args.args)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very breaking change since the CLI now returns 1 (which is the standard code for "failure") on a successful execution.

33 changes: 33 additions & 0 deletions twine/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,36 @@
# limitations under the License.
from __future__ import absolute_import, division, print_function
from __future__ import unicode_literals

import glob
import os.path

__all__ = []


def _group_wheel_files_first(files):
if not any(fname for fname in files if fname.endswith(".whl")):
# Return early if there's no wheel files
return files

files.sort(key=lambda x: -1 if x.endswith(".whl") else 0)

return files


def _find_dists(dists):
uploads = []
for filename in dists:
if os.path.exists(filename):
uploads.append(filename)
continue
# The filename didn't exist so it may be a glob
files = glob.glob(filename)
# If nothing matches, files is []
if not files:
raise ValueError(
"Cannot find file (or expand pattern): '%s'" % filename
)
# Otherwise, files will be filenames that exist
uploads.extend(files)
return _group_wheel_files_first(uploads)
Loading