From d06dd05298d74b23408cc77e05e3d75fb52c529b Mon Sep 17 00:00:00 2001 From: a-tal Date: Wed, 8 Jul 2015 13:49:17 -0700 Subject: [PATCH] adds tests for source_[label|url] and py-info --- README.rst | 1 + pypackage/commands.py | 20 +++++++++++++----- pypackage/config.py | 1 + test/conftest.py | 32 +++++++++++++++++++++++++++++ test/test_commands.py | 47 +++++++++++++++++++++++++++++++++++++++++++ test/test_config.py | 18 +++++++++++++++++ test/test_installs.py | 17 ++++++++++++++++ 7 files changed, 131 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index ac455e0..6b77ddf 100644 --- a/README.rst +++ b/README.rst @@ -35,6 +35,7 @@ Features - automatic version, author, maintainer and email(s) detection (perfers __init__.py, __version__.py) - curses front-end to python classifiers selection +- easy display of installed python package metadata with ``py-info `` Example, "Hello World" application: ----------------------------------- diff --git a/pypackage/commands.py b/pypackage/commands.py index 57d4a0f..9d0ad34 100644 --- a/pypackage/commands.py +++ b/pypackage/commands.py @@ -8,6 +8,8 @@ """ +from __future__ import print_function + import sys import pkg_resources @@ -101,12 +103,20 @@ def info(): env = pkg_resources.Environment() separator = False for arg in sys.argv[1:]: - pkg = env[pkg_resources.safe_name(arg)][0] - if not pkg: - print("The package {} was not found.".format(arg)) + try: + pkg = env[pkg_resources.safe_name(arg)][0] + except IndexError: + print( + "The package {} was not found.".format(arg), + file=sys.stderr, + ) continue - elif pkg.PKG_INFO != "METADATA": - print("The package {} does not use metadata.".format(arg)) + + if pkg.PKG_INFO != "METADATA": + print( + "The package {} does not use metadata.".format(arg), + file=sys.stderr, + ) continue # this is without a doubt the dumbest line of code I have written diff --git a/pypackage/config.py b/pypackage/config.py index 1e45105..d601fb2 100644 --- a/pypackage/config.py +++ b/pypackage/config.py @@ -467,6 +467,7 @@ class Metadata(object): name = getattr(self, "name", undef) version = getattr(self, "version", undef) summary = getattr(self, "description", undef) + description = summary home_page = getattr(self, "url", undef) url = home_page author = getattr(self, "author", undef) diff --git a/test/conftest.py b/test/conftest.py index 3f8292d..a55d106 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -174,6 +174,38 @@ def only_binary(request, new_module): return new_module, filename +def random_str(length): + """Returns a random mixed case string of length provided.""" + + def _random_chr(): + if random.randint(0, 1): + return chr(random.choice(range(65, 91))) + else: + return chr(random.choice(range(97, 122))) + return "".join([_random_chr() for _ in range(length)]) + + +@pytest.fixture +def source_release(request, new_package): + """Creates a package with source_label and source_url filled in. + + Returns: + tuple of module root directory, source_label, source_url + """ + + new_module, pkg_root = new_package + source_label = random_str(40) + source_url = "http://{}.com/{}".format(random_str(7), random_str(12)) + with open(os.path.join(new_module, META_NAME), "w") as openmeta: + openmeta.write(( + '{{"packages": ["find_packages()"], "source_label": "{}", ' + '"source_url": "{}"}}' + ).format(source_label, source_url)) + + request.addfinalizer(module_cleanup) + return new_module, source_label, source_url + + def module_cleanup(): """Used to cleanup the testing module.""" diff --git a/test/test_commands.py b/test/test_commands.py index 7cd5d73..cb179d6 100644 --- a/test/test_commands.py +++ b/test/test_commands.py @@ -107,5 +107,52 @@ def test_setup_entry__multilocations(reset_sys_argv): assert patched_config.call_count == 2 +def test_info(reset_sys_argv, capfd): + """Ensure we're looking up and dumping package metadata to stdout.""" + + sys.argv = ["py-info", "pytest"] + commands.info() + stdout, stderr = capfd.readouterr() + + assert not stderr + assert "Name: pytest" in stdout + assert "License: MIT license" in stdout + + +def test_info__pkg_not_found(reset_sys_argv, capfd): + """Ensure the error message when a package is not found.""" + + sys.argv = ["py-info", "some-random-non-existant-package"] + commands.info() + out, err = capfd.readouterr() + + assert not out + assert "The package some-random-non-existant-package was not found." in err + + +def test_info__pkg_without_metadata(reset_sys_argv, capfd): + """Verify the error message for a metadata-less package.""" + + mock_pkg = mock.Mock() + mock_pkg.PKG_INFO = "PKG-INFO" + + mockenv = mock.Mock() + mockenv.__getitem__ = mock.Mock(return_value=[mock_pkg]) + + environment_patch = mock.patch.object( + commands.pkg_resources, + "Environment", + return_value=mockenv, + ) + + sys.argv = ["py-info", "foo-bar"] + with environment_patch: + commands.info() + + out, err = capfd.readouterr() + assert not out + assert "The package foo-bar does not use metadata." in err + + if __name__ == "__main__": pytest.main(["-rx", "-v", "--pdb", __file__]) diff --git a/test/test_config.py b/test/test_config.py index 6649f34..2c1e51f 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -1,6 +1,8 @@ """Tests for pypackages' config object and helper functions.""" +import io +import os import json import mock import pytest @@ -303,5 +305,21 @@ def test_long_read_errors_buried(with_readme): assert not conf._long_read_in_setup +def test_write_pkg_info_shim(source_release): + """Confirm the metadata shim to write out our extra metadata params.""" + + pkg_root, source_label, source_url = source_release + conf = config.get_config(pkg_root) + + conf.metadata.write_pkg_info(pkg_root) + pkg_info_file = os.path.join(pkg_root, "PKG-INFO") + with io.open(pkg_info_file, "r", encoding="utf-8") as openinfo: + pkg_info = openinfo.read() + + assert pkg_info.startswith("Metadata-Version: 1.0") + assert "Source-Label: {}".format(source_label) in pkg_info + assert "Source-Url: {}".format(source_url) in pkg_info + + if __name__ == "__main__": pytest.main(["-rx", "-v", "--pdb", __file__]) diff --git a/test/test_installs.py b/test/test_installs.py index 6bcaee6..db8a11f 100644 --- a/test/test_installs.py +++ b/test/test_installs.py @@ -94,5 +94,22 @@ def test_long_description_as_file(with_readme): }) +def test_source_tags(source_release): + """Ensure the source url and label are in the package metadata.""" + + with mock.patch.object(setuptools, "setup") as mocked_setup: + install() + + assert sys.argv == ["setup.py", "install"] + package_dir, source_label, source_url = source_release + package = os.path.basename(package_dir) + call_args = mocked_setup.call_args[1] + assert call_args["name"] == package + assert call_args["packages"] == [package] + assert "